TN033: Wersja biblioteki DLL MFC
Uwaga ta opisuje, jak można użyć MFCxx.DLL i MFCxxD.DLL (gdzie x jest numerem wersji MFC) współużytkowane biblioteki dołączane dynamicznie z aplikacji MFC i rozszerzenie DLL.Aby uzyskać więcej informacji na temat bibliotek DLL regularnych zobacz Za pomocą MFC jako część biblioteki DLL.
Ten Uwaga techniczna obejmuje trzy aspekty biblioteki DLL.Ostatnie dwa są dla bardziej zaawansowanych użytkowników:
Jak zbudować Biblioteka DLL rozszerzenia MFC
Jak zbudować aplikację MFC używa wersji biblioteki DLL MFC
Jak MFC współużytkowane biblioteki DLL są implementowane.
Jeśli jesteś zainteresowany budowania biblioteki DLL przy użyciu MFC, używany w aplikacjach MFC nie (jest to regularne DLL), zajrzyj do technicznej Uwaga 11.
Omówienie obsługi MFCxx.DLL: terminologii i plików
Regularne DLL: Użyj regularnych DLL zbudować bibliotekę DLL autonomicznych niektórych klas MFC.Interfejsy granice App/DLL są interfejsy "C", a aplikacja klienta nie ma być Aplikacja MFC.
To jest wersja biblioteki DLL obsługi obsługiwane w wersji 1.0 MFC.Jest on opisany w technicznej Uwaga 11 i próbki MFC zaawansowane pojęcia DLLScreenCap.
[!UWAGA]
Jak z Visual C++ w wersji 4.0 termin USRDLL jest przestarzały i nie został zastąpiony przez regularne biblioteki DLL, które statycznie łączy się MFC.Może również zbudować regularnych biblioteki DLL, która dynamicznie łączy MFC.
MFC 3.0 (i powyżej) obsługuje regularne bibliotek DLL z nowych funkcji, łącznie z klasy OLE i bazy danych.
AFXDLL: to jest również zwany udostępnioną wersję biblioteki MFC.To jest obsługa nowych DLL dodaje MFC 2.0.Samej biblioteki MFC jest liczba bibliotek DLL (opisanych poniżej) i dynamicznie łączy biblioteki DLL, które wymaga aplikacji klienta lub DLL.Interfejsy granice aplikacji/DLL są C + +/ MFC klasy interfejsów.Aplikacja klienta musi być aplikacji MFC.Ten obsługuje wszystkie funkcje MFC 3.0 (wyjątek: UNICODE nie jest obsługiwana dla klas bazy danych).
[!UWAGA]
W Visual C++ w wersji 4.0 DLL tego typu jest nazywana "Rozszerzenie DLL."
Uwaga ta będzie użyć MFCxx.DLL do odwoływania się do całego ustawione MFC DLL, która obejmuje:
Program Debug: MFCxxD.DLL (połączone) i MFCSxxD.LIB (statyczny).
Wydanie: MFCxx.DLL (połączone) i MFCSxx.LIB (statyczny).
Program Unicode Debug: MFCxxUD.DLL (połączone) i MFCSxxD.LIB (statyczny).
Wydanie Unicode: MFCxxU.DLL (połączone) i MFCSxxU.LIB (statyczny).
[!UWAGA]
MFCSxx [N] [D].Biblioteki LIB są używane w połączeniu z MFC współużytkowane biblioteki DLL.Biblioteki te zawierają kod, który musi być powiązana statycznie do aplikacji lub DLL.
Łącza aplikacji, do odpowiedniej biblioteki import:
Debugowanie: MFCxxD.LIB
Wydania: MFCxx.LIB
Program Debug Unicode: MFCxxUD.LIB
Wersji Unicode: MFCxxU.LIB
Plik "MFC rozszerzenie DLL" jest zbudowany na MFCxx.DLL (lub inne urządzenie MFC współużytkowane biblioteki DLL).W tym miejscu architektury składników MFC uruchamiane.Jeśli wynikają przydatne klasy z klasy MFC lub tworzenie innego podobnego MFC toolkit można umieścić w bibliotece DLL.Że DLL używa MFCxx.DLL, podobnie jak aplikacja klienta ultimate.Pozwala to na klasy typu liść wielokrotnego użytku, podstawowych klas wielokrotnego użytku i klas wielokrotnego użytku lub widoku dokumentu.
Wady i zalety
Dlaczego należy używać udostępnioną wersję MFC?
Za pomocą współużytkowanej biblioteki mogą skutkować mniejszą aplikacji (minimalny aplikacji, która wykorzystuje większość biblioteki MFC jest mniejsza niż 10 K).
Udostępnioną wersję MFC obsługuje biblioteki DLL rozszerzenia MFC i regularne biblioteki DLL.
Budowanie aplikacji korzystającej z bibliotek MFC jest szybsze niż budowanie statycznie Aplikacja MFC, ponieważ nie jest konieczne powiązanie MFC sam.Jest to szczególnie ważne w debugowania kompilacje, gdy program łączący musi kompaktować informacje debugowania — łącząc się z biblioteki DLL, która już zawiera informacje o debugowaniu, jest mniej informacji debugowania do kompaktowania w aplikacji.
Dlaczego nie należy korzystać udostępnioną wersję MFC:
- Wysyłka aplikacji korzystającej z udostępnionej biblioteki wymaga statku MFCxx.DLL (i innych) biblioteki z programem.MFCxx.DLL jest swobodnie do dystrybucji, podobnie jak wiele bibliotek DLL, ale nadal należy zainstalować biblioteki DLL w programie INSTALATOR.Ponadto muszą dostarczać MSVCRTxx.DLL, który zawiera biblioteki c runtime, która jest używana zarówno przez program, biblioteki MFC DLL, same.
Jak napisać rozszerzenie MFC DLL
Biblioteka DLL rozszerzenia MFC jest biblioteką DLL, zawierający klasy i funkcje napisane ozdobić funkcjonalności klas MFC.Biblioteka DLL rozszerzenia MFC używa udostępnionego biblioteki MFC DLL w taki sam sposób, aplikacja używa, kilka uwagi dodatkowe:
Proces kompilacji jest podobny do budowania aplikacji korzystającej z bibliotek MFC kilka dodatkowych kompilator i program łączący opcje.
Biblioteka DLL rozszerzenia MFC nie ma CWinApp-klasy.
Biblioteka DLL rozszerzenia MFC musi dostarczyć specjalnego DllMain.Dostarcza AppWizard DllMain funkcja, którą można modyfikować.
Biblioteka DLL rozszerzenia MFC zapewniają zazwyczaj inicjacji, aby utworzyć CDynLinkLibrary , jeśli rozszerzenie DLL pragnie wywozić CRuntimeClasses lub zasoby do aplikacji.Klasa pochodna CDynLinkLibrary można stosować, jeśli dla aplikacji danych musi pozostać przez rozszerzenie DLL.
Rozważania te są opisane bardziej szczegółowo poniżej.Powinna również dotyczyć próbki MFC zaawansowane pojęcia DLLHUSK , ponieważ stanowi ono ilustrację:
Budowanie aplikacji przy użyciu bibliotek.(DLLHUSK.EXE jest aplikacja MFC, który dynamicznie łącza do biblioteki MFC również inne biblioteki DLL).
Tworzenie biblioteki DLL rozszerzenia MFC.(Uwaga flagi specjalne, takie jak _AFXEXT używanych w budowaniu biblioteki DLL rozszerzenia)
Dwa przykłady biblioteki DLL rozszerzenia MFC.Pokazuje jeden podstawowa struktura Biblioteka DLL rozszerzenia MFC z ograniczoną wywozu (TESTDLL1) i innych pokazów wywozu całej klasy interfejsu (TESTDLL2).
Zarówno aplikacji klienta i biblioteki DLL rozszerzenia należy użyć tej samej wersji MFCxx.DLL.Należy postępuj zgodnie z Konwencją MFC DLL i zapewniają obu debugowania i handlu detalicznego (/ release) wersja biblioteki DLL rozszerzenia sieci.Pozwala to na programy klienckie do budowania zarówno debugowania i detalicznych wersjach ich wniosków i połączyć je z odpowiednich debugowania lub wersji detalicznej wszystkich bibliotek DLL.
[!UWAGA]
Ponieważ C++ nazwę przekręcona i eksportować problemy, listy eksportowanych z rozszerzeniem DLL mogą być różne dla różnych platform dla bibliotek DLL i debugowania i detaliczne wersje tej samej bibliotece DLL.Detalicznych MFCxx.DLL około 2000 wywiezionego punkty wejścia; Program debug MFCxxD.DLL około 3000 wywiezionego punkty wejścia.
Szybkie Uwaga na zarządzanie pamięcią
W podrozdziale "Zarządzanie pamięcią," pod koniec tego Uwaga techniczna opisuje wykonania MFCxx.DLL z udostępnioną wersję MFC.Informacje, które trzeba znać, aby zaimplementować tylko rozszerzenie DLL opisano tutaj.
MFCxx.DLL i wszystkie biblioteki DLL rozszerzenia ładowane do przestrzeni adresowej aplikacji klienta będzie używać ten sam program przydzielania pamięci, obciążenia zasobów i inne Państwa "globalne" MFC tak, jakby były w tej samej aplikacji.Jest to znaczące, ponieważ biblioteki DLL nie MFC i regularne biblioteki DLL, które statycznie połączyć MFC czy dokładnym przeciwieństwem i mieć każdej biblioteki DLL przydzielania z własnej puli pamięci.
Jeśli biblioteka DLL rozszerzenia przydziela pamięć, że pamięć można swobodnie intermix z innym obiektem przydzielone aplikacji.Ponadto w przypadku awarii aplikacji korzystającej z bibliotek MFC, ochrona systemu operacyjnego utrzymywać integralność innych aplikacji MFC, udostępnianie biblioteki DLL.
Podobnie innych "globalne" MFC, bieżący plik wykonywalny do ładowania zasobów, takich jak są również wspólnie przez aplikację klienta i wszystkie biblioteki DLL rozszerzenia MFC także MFCxx.DLL sobie.
Tworzenie biblioteki DLL rozszerzenia
AppWizard można użyć do utworzenia projektu MFC DLL rozszerzenia i automatycznie generuje odpowiednie kompilator i program łączący ustawienia.Była też generowanie DllMain funkcja, którą można modyfikować.
Jeśli konwertujesz istniejącego projektu do biblioteki DLL rozszerzenia MFC zaczynają się standardowe zasady dotyczące budowania aplikacji za pomocą udostępnionego wersji MFC, a następnie wykonaj następujące czynności:
Dodaj /D_AFXEXT do flagi kompilatora.W oknie dialogowym właściwości projektu wybierz węzeł c i C++.Następnie wybierz kategorię preprocesora.Dodaj _AFXEXT do pola definiowania makra, oddzielając każdy z elementów średnikami.
Usuń /Gy przełącznik kompilatora.W oknie dialogowym właściwości projektu wybierz węzeł c i C++.Następnie wybierz kategorię generowania kodu.Upewnij się, nie włączono opcję "Włącz łączenie poziomu funkcji".Będzie to ułatwić eksportowanie klas, ponieważ program łączący nie spowoduje usunięcia funkcje nieużywane.Jeśli oryginalny projekt jest używany do utworzenia biblioteki DLL regularnych statycznie połączone z MFC, zmiana /MT [d opcję kompilatora, aby Opcje [d.
Tworzenie biblioteki wywozu z /dll opcję łącze.Spowoduje to ustawienie podczas tworzenia nowego celu, okreolająca typ docelowy biblioteki DLL systemu Win32.
Zmienianie plików nagłówka
Celem rozszerzenia DLL jest zazwyczaj eksportować niektóre typowe funkcje do jednego lub więcej aplikacji, które można używać tej funkcji.To definiowania eksportowanie klas i funkcje globalne, które są dostępne dla aplikacji klienta.
W tym celu musi ubezpieczania, że każdy z funkcji elementów członkowskich jest oznaczona jako przywozu lub wywozu jako odpowiedni.Wymaga to deklaracje specjalne: opcję __declspec(dllexport) i __declspec(dllimport).Gdy swoje klasy są używane przez aplikacje klienckie, mają być zadeklarowany jako __declspec(dllimport).Podczas tworzenia biblioteki DLL, sama rozszerzenia, powinien być zadeklarowany jako opcję __declspec(dllexport).Ponadto funkcje muszą być faktycznie wywiezionych, tak, aby programy klienckie powiązać je w czasie ładowania.
Aby wyeksportować całą klasy, użyj AFX_EXT_CLASS w definicji klasy.To makro jest zdefiniowany w ramach jako opcję __declspec(dllexport) po _AFXDLL i _AFXEXT jest zdefiniowany, ale zdefiniowana jako __declspec(dllimport) po _AFXEXT nie jest zdefiniowany._AFXEXTjak opisano powyżej, jest definiowana tylko w Konstruując biblioteki DLL rozszerzenia sieci.Na przykład:
class AFX_EXT_CLASS CExampleExport : public CObject
{ ... class definition ... };
Eksportowanie nie całej klasy
Czasami można eksportować tylko poszczególnych niezbędne członków swojej klasy.Na przykład, jeśli eksportujesz CDialog-klasy, może być tylko należy wyeksportować konstruktora i DoModal wywołania.Można eksportować tych członków, przy użyciu biblioteki DLL.DEF pliku, ale można również użyć AFX_EXT_CLASS w podobny sposób na poszczególnych członków, należy wyeksportować.
Na przykład:
class CExampleDialog : public CDialog
{
public:
AFX_EXT_CLASS CExampleDialog();
AFX_EXT_CLASS int DoModal();
// rest of class definition
.
.
.
};
Ponieważ są już eksportowanie wszystkich członków klasy tej czynności może uruchomić dodatkowe problem.Przyczyną problemu jest sposób tej pracy makra MFC.Kilka makra pomocnika MFC firmy faktycznie zadeklarować lub definiowania danych członków.W związku z tym członkowie tych danych będzie musiała być wywożone z biblioteki DLL.
Na przykład DECLARE_DYNAMIC makro jest zdefiniowany następująco Konstruując biblioteki DLL rozszerzenia:
#define DECLARE_DYNAMIC(class_name) \
protected: \
static CRuntimeClass* PASCAL _GetBaseClass(); \
public: \
static AFX_DATA CRuntimeClass class##class_name; \
virtual CRuntimeClass* GetRuntimeClass() const; \
Wiersz rozpoczynający się "statyczne AFX_DATA" jest zadeklarowanie obiektu statycznego wewnątrz klasy użytkownika.Aby poprawnie wyeksportować tej klasy i uzyskać dostęp do informacji runtime przez klienta.EXE, należy wyeksportować obiektu statycznego.Ponieważ obiekt statyczny jest zadeklarowana z modyfikatorem AFX_DATA, musisz zdefiniować AFX_DATA za opcję __declspec(dllexport) Konstruując biblioteki DLL i zdefiniowanie go jako __declspec(dllimport) podczas konstruowania klient programu wykonywalnego.
Jak powiedziano wcześniej, AFX_EXT_CLASS jest już zdefiniowana w ten sposób.Wystarczy porozumiewają się AFX_DATA być taka sama, jak AFX_EXT_CLASS wokół definicji klasy użytkownika.
Na przykład:
#undef AFX_DATA
#define AFX_DATA AFX_EXT_CLASS
class CExampleView : public CView
{
DECLARE_DYNAMIC()
// ... class definition ...
};
#undef AFX_DATA
#define AFX_DATA
MFC zawsze używa AFX_DATA symbol na elementy danych definiuje w makrach, więc ta technika będą działać dla wszystkich takich scenariuszy.Na przykład, będą działać dla DECLARE_MESSAGE_MAP.
[!UWAGA]
Jeśli eksportujesz całej klasy, a nie wybrane składniki klasy automatycznie eksportowane są dane statyczne członków.
Można użyć tej samej techniki umożliwiające automatyczne eksportowanie CArchive ekstrakcji operator dla klasy użycia tego DECLARE_SERIAL i IMPLEMENT_SERIAL makr.Eksportuj operator archiwum przez korekcji deklaracje klas (znajdujący się w.Plik H) z następującego kodu:
#undef AFX_API
#define AFX_API AFX_EXT_CLASS
<your class declarations here>
#undef AFX_API
#define AFX_API
Ograniczenia _AFXEXT
Można użyć _AFXEXT pre-processor symbol swoje rozszerzenie DLL tak długo, jak nie ma wiele warstw z rozszerzeniem dll.Jeśli mają rozszerzenie DLL wywołania lub pochodzić od klasy własne rozszerzenie DLL, które następnie wynikają z klas MFC, należy użyć symbolu preprocesora, aby uniknąć niejednoznaczności.
Problem polega na tym w Win32, musi jawnie deklarować wszelkie dane jako opcję __declspec(dllexport) jeśli mają zostać wywiezione z biblioteki DLL, i __declspec(dllimport) , jeżeli jest przywożone z biblioteki DLL.Podczas definiowania _AFXEXT, nagłówki MFC, upewnij się, że AFX_EXT_CLASS jest poprawnie zdefiniowany.
Gdy masz wiele warstw, jeden symbol takich jak AFX_EXT_CLASS nie jest wystarczające, ponieważ rozszerzenie DLL może być eksportowanie nowych klas a także importowanie innych klas z biblioteki DLL rozszerzenia innej.W celu rozwiązania tego problemu, można użyć specjalnych symboli preprocesora wskazujący budowania DLL sam kontra przy użyciu biblioteki DLL.Załóżmy na przykład, dwa rozszerzenie DLL, A.DLL i B.DLL.Każdy z nich niektóre klasy A.H i B.H, odpowiednio na wywóz.B.dll korzysta z klas z A.DLL.Pliki nagłówków będzie wyglądać następująco:
/* A.H */
#ifdef A_IMPL
#define CLASS_DECL_A __declspec(dllexport)
#else
#define CLASS_DECL_A __declspec(dllimport)
#endif
class CLASS_DECL_A CExampleA : public CObject
{ ... class definition ... };
/* B.H */
#ifdef B_IMPL
#define CLASS_DECL_B __declspec(dllexport)
#else
#define CLASS_DECL_B __declspec(dllimport)
#endif
class CLASS_DECL_B CExampleB : public CExampleA
{ ... class definition .. };
Podczas tworzenia A.DLL jest zbudowany z /D A_IMPL i podczas tworzenia B.DLL jest zbudowany z /D B_IMPL.Za pomocą oddzielnych symbole dla każdej biblioteki DLL, jest eksportowany CExampleB i CExampleA jest przywożone podczas konstruowania B.DLL.CExampleA jest wywożone podczas konstruowania A.DLL i przywożone, gdy jest używana przez B.DLL (lub innego klienta).
Ten typ warstwy nie można wykonać przy użyciu wbudowanych AFX_EXT_CLASS i _AFXEXT symboli preprocesora.Techniki opisane powyżej rozwiązuje ten problem, w sposób nie w przeciwieństwie do mechanizmu MFC sam używa podczas konstruowania jego rozszerzenie OLE, bazy danych i sieciowe biblioteki DLL.
Eksportowanie nie całej klasy
Ponownie należy zwrócić szczególną uwagę w przypadku, gdy nie eksportujesz całej klasy.Należy zapewnić prawidłowo wyeksportowane elementy niezbędne dane utworzone przez makra MFC.Można to zrobić przez re-defining AFX_DATA do makra użytkownika określonej klasy.Powinno to dowolnym czasie nie eksportujesz całej klasy.
Na przykład:
// A.H
#ifdef A_IMPL
#define CLASS_DECL_A _declspec(dllexport)
#else
#define CLASS_DECL_A _declspec(dllimport)
#endif
#undef AFX_DATA
#define AFX_DATA CLASS_DECL_A
class CExampleA : public CObject
{
DECLARE_DYNAMIC()
CLASS_DECL_A int SomeFunction();
//class definition
.
.
.
};
#undef AFX_DATA
#define AFX_DATA
Funkcja DllMain
Poniżej przedstawiono dokładny kod, który należy umieścić w pliku głównym źródłem dla użytkownika biblioteki DLL rozszerzenia.To powinna pochodzić po zawiera standardowe.Należy zauważyć, że użycie AppWizard do tworzenia starter pliki z rozszerzeniem DLL, dostarcza mu DllMain dla Ciebie.
#include "afxdllx.h"
static AFX_EXTENSION_MODULE extensionDLL;
extern "C" int APIENTRY
DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID)
{
if (dwReason == DLL_PROCESS_ATTACH)
{
// Extension DLL one-time initialization
if (!AfxInitExtensionModule(
extensionDLL, hInstance))
return 0;
// TODO: perform other initialization tasks here
}
else if (dwReason == DLL_PROCESS_DETACH)
{
// Extension DLL per-process termination
AfxTermExtensionModule(extensionDLL);
// TODO: perform other cleanup tasks here
}
return 1; // ok
}
Wywołanie AfxInitExtensionModule przechwytuje modułów uruchomieniowy (CRuntimeClass struktur) jak również jego fabryk obiektu (COleObjectFactory obiektów) do użycia przy późniejszym CDynLinkLibrary tworzony jest obiekt.Wywołanie (opcjonalnie) AfxTermExtensionModule pozwala MFC Oczyszczanie biblioteki DLL rozszerzenia podczas każdego procesu odłącza (które się dzieje, kiedy proces lub biblioteka DLL jest wyładowane w wyniku FreeLibrary call) z biblioteki DLL rozszerzenia.Ponieważ większość rozszerzenie DLL nie są ładowane dynamicznie (zwykle są łączone za pośrednictwem ich importu biblioteki), wywołanie AfxTermExtensionModule zazwyczaj nie jest konieczne.
Jeśli aplikacja ładuje i zwalnia biblioteki DLL rozszerzenia dynamicznie, należy wywołać AfxTermExtensionModule jak wykazano powyżej.Należy także użyć AfxLoadLibrary i AfxFreeLibrary (zamiast funkcji Win32 LoadLibrary i FreeLibrary) Jeśli aplikacja korzysta z wielu wątków lub dynamicznie ładuje rozszerzeniem DLL.Za pomocą AfxLoadLibrary i AfxFreeLibrary gwarantują, że kod uruchamiania i zamykania, który jest wykonywany, gdy biblioteka DLL rozszerzenia jest załadowane lub wyładowane nie doprowadzić do uszkodzenia globalnego MFC.
Plik nagłówkowy AFXDLLX.H zawiera definicje szczególne struktury biblioteki DLL rozszerzenia, takie jak definicja AFX_EXTENSION_MODULE i CDynLinkLibrary.
Globalny extensionDLL muszą być zadeklarowane, jak pokazano.W odróżnieniu od wersji 16-bitowej biblioteki MFC, można przydzielić pamięci i wywoływać funkcje MFC w tym czasie, ponieważ MFCxx.DLL jest w pełni zainicjowany przez czas na DllMain jest wywoływana.
Udostępnianie zasobów i klasy
Proste MFC rozszerzenie DLL należy eksportować tylko kilka funkcji o niskiej przepustowości do aplikacji klienta i nic więcej.Więcej intensywne bibliotek DLL interfejsu użytkownika może być eksportowanie zasobów i klas C++ do aplikacji klienta.
Eksportowanie zasobów odbywa się poprzez listę zasobów.W każdej aplikacji jest pojedynczo połączonej listy z CDynLinkLibrary obiektów.Podczas wyszukiwania zasobów, większość standardowych implementacje MFC, które ładują zasoby przyjrzeć bieżącego modułu zasobów (AfxGetResourceHandle) i jeżeli nie znaleziono walk listy CDynLinkLibrary obiektów próby załadowania żądanego zasobu.
Dynamiczne tworzenie obiektów C++ podana nazwa klasy C++ jest podobny.Mechanizm deserializacji obiektu MFC musi mieć wszystkie CRuntimeClass obiekty zarejestrowane tak, aby go odtworzyć, tworząc dynamicznie C++ obiektu typu wymagane na podstawie co został wcześniej przechowywane.
Jeśli chcesz, aby aplikacja klienta, aby użyć klasy użytkownika biblioteki DLL rozszerzenia, które są DECLARE_SERIAL, a następnie trzeba będzie wyeksportować klasy, aby były widoczne dla aplikacji klienta.Również w tym celu należy idzie CDynLinkLibrary listy.
W przypadku próbki MFC zaawansowane pojęcia DLLHUSK, listy wyglądać:
head -> DLLHUSK.EXE - or - DLLHUSK.EXE
| |
TESTDLL2.DLL TESTDLL2.DLL
| |
TESTDLL1.DLL TESTDLL1.DLL
| |
| |
MFC90D.DLL MFC90.DLL
MFCxx.DLL jest zazwyczaj ostatni na liście klasy i zasobów.MFCxx.DLL zawiera wszystkie standardowe zasoby MFC, w tym prompt ciągi dla wszystkich identyfikatorów standardowego polecenia.Umieszczając go na końcu listy umożliwia bibliotek DLL i aplikacja klienta nie ma własną kopię zasobów standardowych MFC, ale aby polegać na zasobach udostępnionych w MFCxx.DLL zamiast.
Scalanie zasobów i klasy nazwy wszystkich plików DLL do przestrzeni nazw aplikacji klienta ma niekorzystnej sytuacji, które mają być ostrożnym, jakie identyfikatory lub nazwy, które można wybrać.Można oczywiście wyłączyć tę funkcję przez nie eksportujących albo zasobów lub CDynLinkLibrary obiektu do aplikacji klienta.DLLHUSK próbki zarządza obszar nazw zasobu udostępnionego przy użyciu wielu plików nagłówkowych.Zobacz 35 Uwaga techniczne więcej porad na temat używania plików udostępnionych zasobów.
Inicjowanie biblioteki DLL
Jak wspomniano powyżej, zazwyczaj warto utworzyć CDynLinkLibrary obiekt, aby wyeksportować zasobów i klas do aplikacji klienta.Należy podać punkt wejścia wywożonych do zainicjowania biblioteki DLL.Minimalny zestaw jest void rutynowych, nie przyjmuje żadnych argumentów i zwraca nic, ale można nadać dowolną.
Każdej aplikacji klienckiej, która chce korzystać z biblioteki DLL musi wywołać ten inicjacji, jeżeli użyjesz tej metody.Również może przydzielić to CDynLinkLibrary obiekt w sieci DllMain tuż po telefonicznej AfxInitExtensionModule.
Procedura inicjowania należy utworzyć CDynLinkLibrary obiektu w bieżącej aplikacji sterty, wired do użytkownika rozszerzenie DLL informacji.Można to zrobić z następujących czynności:
extern "C" extern void WINAPI InitXxxDLL()
{
new CDynLinkLibrary(extensionDLL);
}
Nazwa rutynowych, InitXxxDLL w tym przykładzie może być dowolną inną.Nie trzeba być extern "C", ale tak powoduje, że lista wywóz łatwiejsze w obsłudze.
[!UWAGA]
Użycie na rozszerzenie DLL z regularnych biblioteki DLL, należy wyeksportować tej funkcji inicjowania.Ta funkcja musi o nazwie regularnych dll przed rozpoczęciem korzystania z jakichkolwiek klas DLL rozszerzeń lub zasobów.
Eksportowanie wpisów
Prosty sposób wyeksportować swoje klasy jest użycie __declspec(dllimport) i opcję __declspec(dllexport) na każdej klasy i funkcja globalna, które chcesz eksportować.Dzięki znacznie łatwiejsze, ale jest mniej skuteczne niż nazewnictwa każdego punktu wejścia (opisanych poniżej), ponieważ ma mniejsze możliwości kontroli nad jakie funkcje są wywożone i nie można wyeksportować funkcji przez wartość porządkową.TESTDLL1 i TESTDLL2 ta metoda umożliwia eksportowanie ich wpisów.
Bardziej efektywną metodą (i metoda używana przez MFCxx.DLL) jest ręcznie wyeksportować każdy wpis nazywając każdego wpisu w.DEF pliku.Ponieważ firma Microsoft są eksportowane selektywne wywozu z naszą bibliotekę DLL (to znaczy nie wszystko), możemy należy zdecydować, które określonego interfejsy, które chcemy eksportować.Jest to trudne, ponieważ należy określić zniekształcone nazwy, aby program łączący w formie zapisów.DEF pliku.Nie należy eksportować wszystkich klas C++, chyba że trzeba mieć łącza symbolicznego.
Jeśli wypróbowano klasy C++ wywozu z.DEF pliku, zanim można rozwijać narzędzia, aby automatycznie wygenerować tej listy.Można to zrobić przy użyciu łączy dwa etapy procesu.Łącze biblioteki DLL raz z wywozu i pozostawić program łączący do wygenerowania.Plik mapy..Plik mapy można wygenerować listę funkcji, które powinny być wyeksportowane, tak aby z niektórych rozmieszczanie można używać do wygenerowania wpisów EKSPORTU dla użytkownika.DEF pliku.Lista wywóz MFCxx.DLL OLE i biblioteki DLL rozszerzenia bazy danych, kilka tysięcy w liczbie, został wygenerowany z takiego procesu (chociaż nie jest całkowicie zautomatyzowany i wymaga niektóre strony dostrajania raz co pewien czas).
CWinApp vs.CDynLinkLibrary
Biblioteka DLL rozszerzenia MFC nie ma CWinApp-uzyskane obiektu własnej; Zamiast tego należy pracować z CWinApp-uzyskane obiektu aplikacji klienta.Oznacza to, aplikacja klienta i tak dalej właścicielem pompy główne wiadomości, pętlę bezczynności.
Jeśli biblioteka DLL rozszerzenia MFC musi być dodatkowych danych dla każdej aplikacji, może uzyskać nową klasę z CDynLinkLibrary i utworzyć go w InitXxxDLL, rutynowe opisano powyżej.Podczas uruchamiania, biblioteka DLL można sprawdzić listę bieżącej aplikacji CDynLinkLibrary obiektów, aby znaleźć jeden dla tej określonej biblioteki DLL rozszerzenia.
Korzystanie z zasobów w danej implementacji biblioteki DLL
Jak wspomniano powyżej, obciążenia zasobów domyślne prowadzi wykaz CDynLinkLibrary obiektów szukasz pierwszy plik EXE lub DLL, która ma żądanego zasobu.Wszystkie interfejsy API MFC, jak również wszystkie używa wewnętrznego kodu AfxFindResourceHandle do listy zasobów, aby znaleźć dowolny zasób, niezależnie od tego, gdzie może zamieszkiwać walk.
Jeśli chcesz załadować tylko zasoby z określonego miejsca użycia interfejsów API AfxGetResourceHandle i AfxSetResourceHandle zapisać stary uchwyt i ustawić nowy uchwyt.Pamiętaj przywrócić stary dojścia do zasobu przed zwróceniem się do aplikacji klienta.Próbki TESTDLL2 używa tego podejścia do jawnego ładowania menu.
Idzie na liście ma wady, że jest nieco wolniejsze i wymaga zarządzania zakresami identyfikator zasobu.Posiada zaletą aplikacji klienckiej, która łączy kilka bibliotek DLL rozszerzenia można użyć dowolnego dostarczonych do biblioteki DLL zasobów bez konieczności określania uchwyt instancji DLL.AfxFindResourceHandleInterfejs API służy do chodzenia listy zasobów do wyszukiwania dla danego dopasowania.To nazwa i typ zasobu i zwraca uchwyt zasobów, którym najpierw ustalono (lub NULL).
Aplikacja używa wersji biblioteki DLL
Wymagania aplikacji
Aplikacji korzystającej z udostępnioną wersję MFC, należy wykonać kilka prostych reguł:
Musi on mieć CWinApp obiekt i wykonaj standardowe zasady dotyczące pompy wiadomości.
Każde pozwolenie na wywóz musi zostać skompilowany z zestawem flag wymagana kompilator (patrz poniżej).
Go połączyć z biblioteki import MFCxx.Przez ustawienie flagi kompilatora wymagane nagłówki MFC ustalenie w czasie łącze biblioteki, które aplikacji należy połączyć z.
Aby uruchomić plik wykonywalny, MFCxx.DLL musi być na ścieżce lub w katalogu systemu Windows.
Budowanie ze środowiska programowania
Jeśli używasz wewnętrznego makefile większość standardowych wartości domyślnych, można łatwo zmienić projektu, aby utworzyć wersję biblioteki DLL.
Następującego kroku założono, że masz prawidłowego działania aplikacji MFC związane z NAFXCWD.LIB (dla debugowania) i NAFXCW.LIB (do sprzedaży detalicznej) i chcesz, aby przekonwertować go do używania udostępnionego wersja biblioteki MFC.Z środowiska Visual C++ i projekt wewnętrzny plik.
- Na projektów menu, kliknij Właściwości.W Ogólne strony pod Project domyślnie, ustaw Microsoft Foundation Classes MFC wykorzystania w bibliotece DLL udostępnione (MFCxx(d).dll).
Budynek z NUPEWNIJ
Jeśli są za pomocą funkcji zewnętrznych makefile Visual C++ lub bezpośrednio z NUPEWNIJ będzie makefile, do obsługi kompilator i program łączący opcje edycji
Flagi kompilatora wymagane:
- / OPCJE D_AFXDLL
/ D_AFXDLL
Standardowych nagłówków MFC konieczne symbol ten należy określić:
- OPCJE
Aplikacja musi używać wersji biblioteki DLL biblioteki uruchomieniowej c
Wszystkie pozostałe flagi kompilatora wykonaj domyślne MFC (na przykład _DEBUG debugowania).
Edytuj listę linker bibliotek.Zmiana NAFXCWD.LIB do MFCxxD.LIB i zmienić NAFXCW.LIB MFCxx.LIB.Zamień LIBC.LIB z MSVCRT.LIB.Jak z innych bibliotek MFC jest ważne, że MFCxxD.LIB jest umieszczana przed wszelkie biblioteki c runtime.
Opcjonalnie dodaj /D_AFXDLL zarówno sprzedaży detalicznej, jak i debugowe opcje kompilatora zasobu (który faktycznie kompiluje zasoby z /R).Dzięki temu program wykonywalny końcowego mniejszych udostępnianie zasobów, które są obecne w biblioteki MFC DLL.
Pełnej przebudowy jest wymagane, po wprowadzeniu tych zmian.
Tworzenie próbek
Większość programów MFC próbki mogą być wbudowane w Visual C++ lub z udostępnionego MAKEFILE NUPEWNIJ zgodny z wiersza polecenia.
Aby przekonwertować dowolne z tych próbek, aby użyć MFCxx.DLL, można załadować.Klucz aktywacji Wielokrotnej plików w programie Visual C++ i ustaw opcje projektu, jak opisano powyżej.Jeśli używasz kompilacji NUPEWNIJ, można określić "AFXDLL = 1" na NUPEWNIJ wiersza polecenia oraz że zbuduje próbki przy użyciu bibliotek MFC.
Próbki MFC zaawansowane pojęcia DLLHUSK jest zbudowany z wersją biblioteki MFC DLL.Ten przykład ilustruje nie tylko sposób budowania aplikacji związanych z MFCxx.DLL, ale ilustruje również inne funkcje opcji opakowania MFC DLL, takich jak biblioteki DLL rozszerzenia MFC opisanych dalej w tym Uwaga techniczna.
Opakowania notatek
Wersji handlowej bibliotek DLL (MFCxx [N].Biblioteka DLL) są swobodnie do dystrybucji.W wersji bibliotek DLL nie są swobodnie do dystrybucji i stosowane są tylko w fazie rozwoju aplikacji.
Debugowania biblioteki DLL są udostępnione informacje debugowania.Za pomocą debugera Visual C++, można śledzić wykonywanie aplikacji, jak również biblioteki DLL.Wersji bibliotek DLL (MFCxx [N].Biblioteka DLL) nie zawierają informacji o debugowaniu.
Jeśli dostosować i przebudować biblioteki DLL, następnie należy wywołać je coś innego niż plik "MFCxx" The SRC MFC MFCDLL.Klucz aktywacji Wielokrotnej opisuje opcje kompilacji i zawiera logikę w celu zmiany nazwy biblioteki DLL.Zmiana nazw plików jest konieczne, ponieważ tych bibliotek DLL potencjalnie są współużytkowane przez wiele aplikacji MFC.Posiadające niestandardową wersję biblioteki MFC DLL Zamień te zainstalowane w systemie mogą przerwać innej aplikacji MFC za pomocą udostępnionego biblioteki MFC DLL.
Odbudowa biblioteki MFC DLL nie jest zalecane.
Sposób implementacji MFCxx.DLL
W poniższej sekcji opisano sposób implementacji biblioteki MFC DLL (MFCxx.DLL i MFCxxD.DLL).Zrozumienie szczegółów tutaj również nie są ważne, jeśli wszystkie chcesz zrobić to biblioteki MFC DLL za pomocą aplikacji.Szczegóły w tym miejscu nie są istotne dla zrozumienia, jak napisać rozszerzenie MFC DLL, ale zrozumienie tej implementacji może pomóc pisać własne biblioteki DLL.
Omówienie wdrażania
Biblioteki MFC DLL naprawdę jest szczególny przypadek Biblioteka DLL rozszerzenia MFC, jak opisano powyżej.Ma bardzo dużej liczby wywozu dla dużej liczby klas.Istnieje kilka dodatkowych rzeczy musimy biblioteki MFC DLL składających się jeszcze bardziej specjalne niż regularne DLL rozszerzenia.
Win32 jest większość pracy
16-Bitowa wersja MFC potrzebne liczba specjalne techniki, łącznie z danymi-app segmentu stosu segmentów specjalne utworzone przez część kodu zestawu 80 x 86, konteksty wyjątku na proces i innych technik.Win32 bezpośrednio obsługuje danych na proces w bibliotece DLL, która jest w większości przypadków.W większości przypadków MFCxx.DLL jest po prostu NAFXCW.LIB zapakowane w bibliotece DLL.Jeśli przyjrzymy się kod źródłowy MFC, znajdziesz bardzo niewiele _AFXDLL # ifdef, ponieważ istnieje bardzo niewiele przypadków szczególnych, które należy wprowadzić.Przypadków szczególnych, które są są specjalnie do zajmowania się Win32 w systemie Windows 3.1 (znany także jako Win32s).Win32s nie nie wsparcia na proces DLL danych bezpośrednio tak biblioteki MFC DLL należy użyć pamięci lokalnej wątku (TLS) Win32 API do uzyskania danych lokalnych procesu.
Wpływ na bibliotece źródeł, dodatkowe pliki
Wpływ _AFXDLL wersji na normalne źródeł biblioteki klas MFC i nagłówki jest stosunkowo niewielkie.Istnieje specjalna wersja pliku (AFXV_DLL.H) jak również dodatkowe nagłówka pliku (AFXDLL_.H) włączone przez AFXWIN głównym.H nagłówka.AFXDLL_.Zawiera nagłówek h CDynLinkLibrary klasy i inne szczegóły dotyczące implementacji, zarówno _AFXDLL aplikacji oraz biblioteki DLL rozszerzenia MFC.AFXDLLX.H nagłówka jest przewidziane budowania MFC DLL rozszerzenia (zobacz powyżej szczegółowe informacje).
Regularne źródeł do biblioteki MFC w MFC SRC mają niektóre dodatkowy kod warunkowe, pod _AFXDLL # ifdef.Plik źródłowy dodatkowe (DLLINIT.CPP) zawiera dodatkowy kod inicjowania biblioteki DLL i przyklejanie innych udostępnionych wersji MFC.
Aby utworzyć wersję udostępnionego MFC, są dostarczane pliki dodatkowe.(Zobacz poniżej szczegółowe informacje na temat sposobu tworzenia biblioteki DLL).
Dwa.DEF pliki są używane do eksportowania punkty wejścia MFC DLL debugowania (MFCxxD.DEF) i Zwolnij (MFCxx.DEF) wersji biblioteki DLL.
.Plik RC (MFCDLL.RC) zawiera wszystkie standardowe zasoby MFC i zasobów VERSIONINFO dla biblioteki DLL.
A.Plik CLW (MFCDLL.CLW) jest świadczone, aby umożliwić przeglądanie MFC klasy przy użyciu ClassWizard.Uwaga: Ta funkcja nie jest określonej wersji biblioteki DLL MFC.
Zarządzanie pamięcią
Aplikacji przy użyciu MFCxx.DLL używa wspólnego programu przydzielania pamięci dostarczonych przez MSVCRTxx.DLL, udostępnionych DLL C runtime.Aplikacja, biblioteki DLL rozszerzenia i również biblioteki MFC DLL, same używać tego programu przydzielania pamięci współużytkowanej.Używając udostępnionego DLL dla alokacji pamięci biblioteki MFC DLL można zaalokować pamięci, który później zostanie zwolniony przez aplikację lub odwrotnie.Ponieważ zarówno w aplikacji i biblioteki DLL, należy użyć tej samej alokatora, nie powinny zastępować C++ globalnego operator new lub operator delete.Te same zasady stosuje się do pozostałej części procedury alokacji pamięci run-time C (takie jak malloc, realloc, wolnegoi inne).
Liczebniki porządkowe i opcję klasy __declspec(dllexport) i DLL nazw
Nie używamy classopcję __declspec(dllexport) funkcji kompilator C++.Zamiast listy wywozu jest dołączony do źródeł biblioteki klas (MFCxx.DEF i MFCxxD.DEF).Eksportowane są tylko te wybierz zestaw punktów wejścia (funkcje i dane).Inne symbole, takie jak MFC prywatnych implementacji funkcji lub klasy, nie są eksportowane cały wywóz, są wykonywane przez Liczebniki bez ciąg nazwy tabeli Nazwa rezydentów lub nierezydentów.
Za pomocą classopcję __declspec(dllexport) może być alternatywą do budowania biblioteki DLL mniejsze, ale w odniesieniu do dużych DLL jak MFC, domyślny, eksportowanie mechanizm ma wydajność i pojemność limitów.
Co to oznacza to wszystkie jest że mamy pakiet dużej ilości funkcji w wersji MFCxx.DLL, który jest tylko około 800 KB bez narażania znacznie wykonanie lub szybkość ładowania.MFCxx.DLL byłaby większa K 100 ta technika nie były używane.To pozwala dodać punkty wejścia dodatkowych na końcu.Plik DEF umożliwia proste przechowywanie wersji bez obniżania wydajności szybkości i wielkości wywozu przez wartość porządkową.Wersja główna korekty w Biblioteka klas MFC zmieni nazwę biblioteki.Oznacza to MFC30.Biblioteka DLL jest przeznaczony do redystrybucji pliku DLL zawierającego wersja 3.0 Biblioteka klas MFC.Uaktualnienie tego pliku DLL powiedzieć, w hipotetyczny 3.1 MFC, biblioteka DLL będzie o nazwie MFC31.Biblioteka DLL zamiast.Ponownie zmodyfikowanie kodu źródłowego MFC produkować niestandardową wersję biblioteki MFC DLL, użyj innej nazwy (i najlepiej bez "MFC") w nazwie.