TN011: używanie MFC jako części biblioteki DLL

W tej notatce opisano regularne biblioteki MFC DLL, które umożliwiają korzystanie z biblioteki MFC w ramach biblioteki linków dynamicznych systemu Windows (DLL). Przyjęto założenie, że znasz biblioteki DLL systemu Windows i sposób ich tworzenia. Aby uzyskać informacje o bibliotekach DLL rozszerzeń MFC, za pomocą których można tworzyć rozszerzenia do biblioteki MFC, zobacz Dll Version of MFC (Wersja biblioteki DLL MFC).

Interfejsy DLL

Zwykłe biblioteki DLL MFC zakładają, że interfejsy między aplikacją a biblioteką DLL są określone w funkcjach przypominających język C lub jawnie wyeksportowanych klasach. Nie można eksportować interfejsów klas MFC.

Jeśli biblioteka DLL i aplikacja chcą używać MFC, obie mają możliwość użycia udostępnionej wersji bibliotek MFC lub statycznego połączenia z kopią bibliotek. Aplikacja i biblioteka DLL mogą używać jednej ze standardowych wersji biblioteki MFC.

Zwykłe biblioteki DLL MFC mają kilka zalet:

  • Aplikacja korzystająca z biblioteki DLL nie musi używać MFC i nie musi być aplikacją Visual C++.

  • W przypadku zwykłych bibliotek DLL MFC, które statycznie łączą się z MFC, rozmiar biblioteki DLL zależy tylko od procedur środowiska uruchomieniowego MFC i C, które są używane i połączone.

  • W przypadku zwykłych bibliotek DLL MFC, które dynamicznie łączą się z MFC, oszczędności pamięci z korzystania z udostępnionej wersji MFC mogą być znaczące. Należy jednak dystrybuować udostępnione biblioteki DLL, Mfc version.dll i Msvvcrt<version.dll>> przy użyciu biblioteki DLL.<

  • Projekt biblioteki DLL jest niezależny od sposobu implementowania klas. Projekt biblioteki DLL eksportuje tylko do żądanych interfejsów API. W związku z tym, jeśli implementacja ulegnie zmianie, regularne biblioteki DLL MFC są nadal prawidłowe.

  • W przypadku zwykłych bibliotek DLL MFC, które statycznie łączą się z MFC, jeśli zarówno biblioteka DLL, jak i aplikacja używają MFC, nie ma problemów z aplikacją, która chce innej wersji MFC niż biblioteka DLL lub odwrotnie. Ponieważ biblioteka MFC jest statycznie połączona z każdą biblioteką DLL lub EXE, nie ma wątpliwości, która wersja jest dostępna.

Ograniczenia interfejsu API

Niektóre funkcje MFC nie mają zastosowania do wersji biblioteki DLL, ze względu na ograniczenia techniczne lub dlatego, że te usługi są zwykle udostępniane przez aplikację. W przypadku bieżącej wersji MFC jedyną funkcją, która nie ma zastosowania, jest CWinApp::SetDialogBkColor.

Kompilowanie biblioteki DLL

Podczas kompilowania zwykłych bibliotek DLL MFC, które statycznie łączą się z MFC, symbole _USRDLL i _WINDLL muszą być zdefiniowane. Kod biblioteki DLL musi być również skompilowany za pomocą następujących przełączników kompilatora:

  • /D_WINDLL oznacza, że kompilacja dotyczy biblioteki DLL

  • /D_USRDLL określa, że tworzysz zwykłą bibliotekę DLL MFC

Należy również zdefiniować te symbole i używać tych przełączników kompilatora podczas kompilowania zwykłych bibliotek DLL MFC, które dynamicznie łączą się z MFC. Ponadto należy zdefiniować symbol _AFXDLL , a kod DLL musi zostać skompilowany przy użyciu następujących elementów:

  • /D_AFXDLL określa, że tworzysz regularną bibliotekę DLL MFC, która dynamicznie łączy się z MFC

Interfejsy (API) między aplikacją a biblioteką DLL muszą być jawnie wyeksportowane. Zalecamy zdefiniowanie interfejsów jako niskiej przepustowości i używanie tylko interfejsów języka C, jeśli to możliwe. Bezpośrednie interfejsy języka C są łatwiejsze do utrzymania niż bardziej złożone klasy języka C++.

Umieść interfejsy API w osobnym nagłówku, który może być dołączony zarówno przez pliki C, jak i C++. Zobacz nagłówek ScreenCap.h w przykładowym pliku DLLScreenCap biblioteki DLLScreenCap MFC Advanced Concepts. Aby wyeksportować funkcje, wprowadź je w EXPORTS sekcji pliku definicji modułu (. DEF) lub uwzględnij __declspec(dllexport) definicje funkcji. Użyj __declspec(dllimport) polecenia , aby zaimportować te funkcje do pliku wykonywalnego klienta.

Musisz dodać makro AFX_MANAGE_STATE na początku wszystkich wyeksportowanych funkcji w zwykłych bibliotekach MFC DLL, które dynamicznie łączą się z MFC. To makro ustawia bieżący stan modułu na ten dla biblioteki DLL. Aby użyć tego makra, dodaj następujący wiersz kodu na początku funkcji wyeksportowanych z biblioteki DLL:

AFX_MANAGE_STATE(AfxGetStaticModuleState( ))

WinMain —> DllMain

Biblioteka MFC definiuje standardowy punkt wejścia Win32 DllMain , który inicjuje obiekt pochodny CWinApp , jak w typowej aplikacji MFC. Umieść wszystkie inicjowanie specyficzne dla biblioteki DLL w metodzie InitInstance , tak jak w typowej aplikacji MFC.

Należy pamiętać, że mechanizm CWinApp::Run nie ma zastosowania do biblioteki DLL, ponieważ aplikacja jest właścicielem głównej pompy komunikatów. Jeśli biblioteka DLL wyświetla moderowe okna dialogowe lub ma własne główne okno ramowe, główna pompa komunikatów aplikacji musi wywołać procedurę wyeksportowaną przez bibliotekę DLL, która wywołuje CWinApp::P reTranslateMessage.

Zobacz przykład DLLScreenCap, aby użyć tej funkcji.

Funkcja DllMain udostępniana przez MFC wywoła metodę CWinApp::ExitInstance klasy, która jest pochodna przed CWinApp zwolnieniem biblioteki DLL.

Łączenie biblioteki DLL

W przypadku zwykłych bibliotek DLL MFC, które statycznie łączą się z MFC, należy połączyć bibliotekę DLL z biblioteką Nafxcwd.lib lub Nafxcw.lib oraz wersją środowisk uruchomieniowych języka C o nazwie Libcmt.lib. Te biblioteki są wstępnie skompilowane i mogą być instalowane przez określenie ich podczas uruchamiania konfiguracji programu Visual C++.

Przykładowy kod

Zobacz przykładowy plik DLLScreenCap przykładowy program MFC Advanced Concepts, aby zapoznać się z kompletnym przykładem. Kilka interesujących kwestii, które należy wziąć pod uwagę w tym przykładzie, są następujące:

  • Flagi kompilatora bibliotek DLL i aplikacji są różne.

  • Wiersze łącza i . Pliki DEF dla biblioteki DLL i te dla aplikacji są różne.

  • Aplikacja korzystająca z biblioteki DLL nie musi znajdować się w języku C++.

  • Interfejs między aplikacją a biblioteką DLL jest interfejsem API, który jest używany przez język C lub C++ i jest eksportowany z biblioteką DLLScreenCap.def.

Poniższy przykład ilustruje interfejs API zdefiniowany w regularnej biblioteki MFC DLL, która statycznie łączy się z MFC. W tym przykładzie deklaracja jest ujęta w extern "C" { } blok dla użytkowników języka C++. Ma to kilka zalet. Po pierwsze sprawia, że interfejsy API bibliotek DLL mogą być używane przez aplikacje klienckie inne niż C++. Po drugie zmniejsza obciążenie biblioteki DLL, ponieważ mangling nazw języka C++ nie zostanie zastosowany do wyeksportowanego nazwy. Na koniec ułatwia jawne dodawanie do elementu . Plik DEF (do eksportowania według porządkowych) bez konieczności martwienia się o mangling nazw.

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

struct TracerData
{
    BOOL bEnabled;
    UINT flags;
};

BOOL PromptTraceFlags(TracerData FAR* lpData);

#ifdef __cplusplus
}
#endif

Struktury używane przez interfejs API nie pochodzą z klas MFC i są zdefiniowane w nagłówku interfejsu API. Zmniejsza to złożoność interfejsu między biblioteką DLL a aplikacją i sprawia, że biblioteka DLL może być użyteczna przez programy języka C.

Zobacz też

Uwagi techniczne według numerów
Uwagi techniczne według kategorii