TN011: Verwenden von MFC als Teil einer DLL

In diesem Hinweis werden reguläre MFC-DLLs beschrieben, mit denen Sie die MFC-Bibliothek als Teil einer Windows Dynamic Link Library (DLL) verwenden können. Es wird davon ausgegangen, dass Sie mit Windows-DLLs und deren Erstellung vertraut sind. Informationen zu MFC-Erweiterungs-DLLs, mit denen Sie Erweiterungen für die MFC-Bibliothek erstellen können, finden Sie unter DLL-Version von MFC.

DLL-Schnittstellen

Reguläre MFC-DLLs übernehmen Schnittstellen zwischen der Anwendung und der DLL werden in C-ähnlichen Funktionen oder explizit exportierten Klassen angegeben. MFC-Klassenschnittstellen können nicht exportiert werden.

Wenn sowohl eine DLL als auch eine Anwendung MFC verwenden möchten, haben beide die Möglichkeit, entweder die freigegebene Version der MFC-Bibliotheken zu verwenden oder eine Statisch-Verknüpfung mit einer Kopie der Bibliotheken zu erstellen. Die Anwendung und DLL können beide eine der Standardversionen der MFC-Bibliothek verwenden.

regelmäßige MFC-DLLs haben mehrere Vorteile:

  • Die Anwendung, die die DLL verwendet, muss MFC nicht verwenden und muss keine Visual C++-Anwendung sein.

  • Bei regulären MFC-DLLs, die statisch mit MFC verknüpfen, hängt die Größe der DLL nur von den verwendeten und verknüpften MFC- und C-Laufzeitroutinen ab.

  • Bei regulären MFC-DLLs, die dynamisch mit MFC verknüpfen, kann die Speichereinsparung bei der Verwendung der gemeinsam genutzten MFC-Version erheblich sein. Sie müssen jedoch die freigegebenen DLLs, Mfc version.dll> und Msvvcrt<version.dll> mit Ihrer DLL verteilen.<

  • Das DLL-Design ist unabhängig davon, wie Klassen implementiert werden. Ihr DLL-Design exportiert nur nach den gewünschten APIs. Wenn sich die Implementierung ändert, sind reguläre MFC-DLLs weiterhin gültig.

  • Bei regulären MFC-DLLs, die statisch mit MFC verknüpfen, wenn sowohl DLL als auch Anwendung MFC verwenden, gibt es keine Probleme mit der Anwendung, die eine andere Version von MFC wünscht als die DLL oder umgekehrt. Da die MFC-Bibliothek statisch mit jeder DLL oder EXE verknüpft ist, gibt es keine Frage, welche Version Sie haben.

API-Einschränkungen

Einige MFC-Funktionen gelten nicht für die DLL-Version, entweder aufgrund technischer Einschränkungen oder weil diese Dienste in der Regel von der Anwendung bereitgestellt werden. Mit der aktuellen Version von MFC ist die einzige Funktion, die nicht anwendbar ist CWinApp::SetDialogBkColor.

Erstellen Ihrer DLL

Beim Kompilieren regulärer MFC-DLLs, die statisch mit MFC verknüpfen, müssen die Symbole _USRDLL _WINDLL definiert werden. Ihr DLL-Code muss auch mit den folgenden Compileroptionen kompiliert werden:

  • /D_WINDLL gibt an, dass die Kompilierung für eine DLL gilt.

  • /D_USRDLL gibt an, dass Sie eine normale MFC-DLL erstellen.

Sie müssen diese Symbole auch definieren und diese Compileroptionen verwenden, wenn Sie reguläre MFC-DLLs kompilieren, die dynamisch mit MFC verknüpft werden. Darüber hinaus muss das Symbol _AFXDLL definiert sein, und Ihr DLL-Code muss mit folgendem Kompiliert werden:

  • /D_AFXDLL gibt an, dass Sie eine normale MFC-DLL erstellen, die dynamisch mit MFC verknüpft wird.

Die Schnittstellen (APIs) zwischen der Anwendung und der DLL müssen explizit exportiert werden. Es wird empfohlen, ihre Schnittstellen als geringe Bandbreite zu definieren und nur C-Schnittstellen zu verwenden, wenn sie möglich sind. Direct C-Schnittstellen sind einfacher zu Standard als komplexere C++-Klassen.

Platzieren Sie Ihre APIs in einem separaten Header, der sowohl von C- als auch von C++-Dateien eingeschlossen werden kann. Ein Beispiel finden Sie im Header ScreenCap.h im Beispiel für MFC Advanced Concepts DLLScreenCap . Um Ihre Funktionen zu exportieren, geben Sie sie in den EXPORTS Abschnitt Ihrer Moduldefinitionsdatei ein (. DEF) oder in Die Funktionsdefinitionen einschließen __declspec(dllexport) . Wird __declspec(dllimport) verwendet, um diese Funktionen in die ausführbare Clientdatei zu importieren.

Sie müssen das AFX_MANAGE_STATE Makro am Anfang aller exportierten Funktionen in regulären MFC-DLLs hinzufügen, die dynamisch mit MFC verknüpfen. Dieses Makro legt den aktuellen Modulstatus auf die 1 für die DLL fest. Um dieses Makro zu verwenden, fügen Sie die folgende Codezeile am Anfang der Funktionen hinzu, die aus der DLL exportiert wurden:

AFX_MANAGE_STATE(AfxGetStaticModuleState( ))

WinMain -> DllMain

Die MFC-Bibliothek definiert den Win32-Standardeinstiegspunkt DllMain , der das von CWinApp abgeleitete Objekt wie in einer typischen MFC-Anwendung initialisiert. Platzieren Sie alle DLL-spezifischen Initialisierungen in der InitInstance-Methode wie in einer typischen MFC-Anwendung.

Beachten Sie, dass der CWinApp::Run-Mechanismus nicht auf eine DLL angewendet wird, da die Anwendung die Standard Nachrichtenpumpe besitzt. Wenn Ihre DLL moduslose Dialogfelder anzeigt oder über ein eigenes Standard Framefenster verfügt, muss die Standard Nachrichtenpumpe ihrer Anwendung eine DLL-exportierte Routine aufrufen, die CWinApp::P reTranslateMessage aufruft.

Weitere Informationen zur Verwendung dieser Funktion finden Sie im DLLScreenCap-Beispiel.

Die DllMain von MFC bereitgestellte Funktion ruft die CWinApp::ExitInstance-Methode Ihrer Klasse auf, die vor CWinApp dem Entladen der DLL abgeleitet wird.

Verknüpfen der DLL

Mit regulären MFC DLLs, die statisch mit MFC verknüpft sind, müssen Sie Ihre DLL mit Nafxcwd.lib oder Nafxcw.lib und mit der Version der C-Laufzeiten mit dem Namen Libcmt.lib verknüpfen. Diese Bibliotheken sind vorinstalliert und können installiert werden, indem sie beim Ausführen des Visual C++-Setups angegeben werden.

Beispielcode

Ein vollständiges Beispiel finden Sie im Beispielprogramm für MFC Advanced Concepts DLLScreenCap. Einige interessante Punkte, die Sie in diesem Beispiel beachten müssen, sind wie folgt:

  • Die Compilerflags der DLL und die der Anwendung unterscheiden sich.

  • Die Verknüpfungslinien und . DEF-Dateien für die DLL und diejenigen für die Anwendung sind unterschiedlich.

  • Die Anwendung, die die DLL verwendet, muss nicht in C++ enthalten sein.

  • Die Schnittstelle zwischen der Anwendung und der DLL ist eine API, die von C oder C++ verwendet werden kann und mit DLLScreenCap.def exportiert wird.

Das folgende Beispiel veranschaulicht eine API, die in einer regulären MFC-DLL definiert ist, die statisch mit MFC verknüpft ist. In diesem Beispiel wird die Deklaration in einen extern "C" { } Block für C++-Benutzer eingeschlossen. Dies hat mehrere Vorteile. Zunächst können Ihre DLL-APIs von Nicht-C++-Clientanwendungen verwendet werden. Zweitens wird der DLL-Aufwand reduziert, da C++-Namens-Mangling nicht auf den exportierten Namen angewendet wird. Schließlich erleichtert es das explizite Hinzufügen zu einem . DEF-Datei (für den Export nach Ordinal), ohne sich gedanken über den Namens-Mangling machen zu müssen.

#ifdef __cplusplus
extern "C" {
#endif  /* __cplusplus */

struct TracerData
{
    BOOL bEnabled;
    UINT flags;
};

BOOL PromptTraceFlags(TracerData FAR* lpData);

#ifdef __cplusplus
}
#endif

Die von der API verwendeten Strukturen werden nicht von MFC-Klassen abgeleitet und werden im API-Header definiert. Dies reduziert die Komplexität der Schnittstelle zwischen der DLL und der Anwendung und macht die DLL von C-Programmen nutzbar.

Siehe auch

Technische Hinweise – nach Nummern geordnet
Technische Hinweise – nach Kategorien geordnet