TN033: Wersja biblioteki DLL MFC

Uwaga ta opisuje w jaki sposób można użyć MFCxx.DLL i MFCxxD.DLL (gdzie x jest numerem wersji MFC) udostępnionych dołączanej dynamicznie biblioteki MFC aplikacjach i bibliotek DLL rozszerzeń. Aby uzyskać więcej informacji o regularnych biblioteki DLL zobacz Przy użyciu MFC jako część biblioteki DLL.

Ta Uwaga techniczna obejmuje trzy aspekty biblioteki DLL. Dwie ostatnie są dla bardziej zaawansowanych użytkowników:

Jeśli jesteś zainteresowany budynek biblioteki DLL przy użyciu MFC, który może być używany w aplikacjach innych niż MFC (to jest nazywana regularnie biblioteki DLL), przeczytaj technicznych Uwaga 11.

Omówienie obsługi MFCxx.DLL: Terminologia i pliki

Regularne DLL: regularne biblioteki DLL umożliwiają budowanie autonomicznych DLL za pomocą niektórych klas MFC. Interfejsy granice App/DLL są interfejsy "C", a aplikacja klienta nie jest aplikacja MFC.

To jest wersja biblioteki DLL pomoc obsługiwane w MFC 1.0. Opisano w technicznych Uwaga 11 i próbki MFC zaawansowane pojęcia DLLTRACE.

Uwaga   W Visual C++ wersja 4.0, termin USRDLL jest przestarzała i został zastąpiony przez regularne biblioteki DLL, które statycznie łączy się MFC. Może również tworzyć regularnych biblioteki DLL, która dynamicznie łączy MFC.

MFC 3.0 (i nowszych) obsługuje regularne biblioteki DLL za pomocą nowej funkcji, w tym klasy OLE i bazy danych.

AFXDLL: jest to również dalej jako udostępnioną wersję biblioteki MFC. To nowe dodane w MFC 2.0 Wsparcie biblioteki DLL. Biblioteki MFC, sam jest w szeregu bibliotek DLL (opisanych poniżej) i aplikacji klienta lub biblioteka DLL dynamicznie łączy biblioteki dll, które wymaga. Interfejsy granice aplikacji/DLL są C + +/ MFC klasy interfejsów. Aplikacja kliencka musi być Aplikacja MFC. Ten obsługuje wszystkie funkcje MFC 3.0 (excption: UNICODE nie jest obsługiwana dla klas bazy danych).

Uwaga   Począwszy od programu Visual C++ w wersji 4.0 tego typu DLL jest określany jako "Rozszerzenie DLL."

Uwaga ta będzie używał MFCxx.DLL odnoszą się do całego, ustawione przez MFC DLL, która zawiera:

Uwaga   MFCSxx [U] [D].LIB biblioteki 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 biblioteki DLL.

Łącza aplikacji w odpowiadających importowanie biblioteki:

"MFC rozszerzenie DLL" jest biblioteka DLL budował MFCxx.DLL (lub inne urządzenie MFC współużytkowane biblioteki DLL). Architektury składników MFC uruchamiane tutaj. Jeśli wynikają użyteczne klasy z klasy MFC lub zbudować innego podobnego MFC toolkit, należy je umieścić w pliku DLL. Że DLL używa MFCxx.DLL, podobnie jak aplikacja klienta końcowego. To pozwala klas wielokrotnego użytku liści, wielokrotnego użycia klas podstawowych i klas wielokrotnego użytku Witajcie.

Uwaganbsp;  &Nie jest konieczne powiązanie z MFCOxx [U] D, D MFCDxx [U] lub MFCNxx [U] D debugowania bibliotek, chyba że aplikacja używa MFC/OLE, bazy danych lub sieci klasy odpowiednio.

Zalety i wady

Dlaczego należy użyć udostępnioną wersję MFC?

Dlaczego użytkownik nie powinien używać udostępnionej wersji MFC:

Jak napisać rozszerzeniem MFC DLL

Biblioteka DLL rozszerzenia MFC jest biblioteki DLL zawierającej funkcje napisane ozdobić funkcjonalności klas MFC i klas. Obsługę debugowania OLE i bazy danych bibliotek DLL (MFCOxxD.DLL i MFCDxxD.DLL) są przykładami rozszerzenie MFC DLL, że używają oni MFCxxD.DLL. Biblioteka DLL rozszerzenia MFC używa udostępnionej biblioteki MFC DLL w ten sam sposób aplikacja używa go, z kilkoma dodatkowe zagadnienia:

Rozważania te są opisane bardziej szczegółowo poniżej. Powinna również dotyczyć próbki MFC zaawansowane pojęcia DLLHUSK ponieważ dowodzi to

Zarówno w aplikacji klienta, jak i wszelkie DLL rozszerzenia muszą używać tej samej wersji MFCxx.DLL. Należy postępować zgodnie z Konwencją MFC DLL i zapewnić zarówno debugowania i detalicznych (/ release) wersja biblioteki DLL rozszerzenia. Pozwala to na programy klienckie do budowania debugowania i detaliczne wersje swoich wniosków i połączyć je z odpowiednim debugowania lub wersji detalicznej wszystkich bibliotek DLL.

Uwaga   Ze względu na C++ nazwa przekręcona i wywóz problem listy wywozu z rozszerzeniem DLL może się różnić pomiędzy debugowania i sprzedaży detalicznej wersji tej samej biblioteki DLL i biblioteki DLL dla różnych platform. 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ą

Sekcja zatytułowana "Zarządzanie pamięcią," pod koniec tego Uwaga techniczna, opisuje życie MFCxx.DLL z udostępnioną wersję MFC. Informacje, które trzeba znać, aby wdrożyć tylko rozszerzenie DLL opisanej tutaj.

MFCxx.DLL i wszystkie DLL rozszerzenia ładowane do przestrzeni adresowej aplikacji klienta będzie używał tych samych przydzielania pamięci, obciążenie zasobów i innych państw "globalnego" MFC tak, jakby były one w tej samej aplikacji. Jest to istotne, ponieważ biblioteki DLL nie MFC i regularne biblioteki dll, które statycznie połączyć MFC nie dokładnym przeciwieństwem i mieć każdej biblioteki DLL alokacji z własnej puli pamięci.

Jeśli biblioteka DLL rozszerzenia przydziela pamięć, a następnie tej pamięci mogą swobodnie intermix z innych obiektów przydzielony aplikacji. Ponadto jeżeli aplikacji, która używa bibliotek MFC awarii, ochrony systemu operacyjnego będzie zachować integralność jakakolwiek inna aplikacja MFC, udostępnianie biblioteki DLL.

Podobnie państw "globalnego" MFC, jak bieżący plik wykonywalny, który obciążenia zasobów, również są udostępniane między aplikacją kliencką i wszystkie MFC DLL rozszerzenia jak również MFCxx.DLL, sam.

Tworzenie biblioteki DLL rozszerzenia

AppWizard można używać do tworzenia projektu DLL rozszerzenia MFC i automatycznie wygeneruje ustawienia konsolidator i odpowiednie kompilatora. Był również generować funkcję DllMain , którą można modyfikować.

Jeśli konwertujesz istniejącego projektu do rozszerzenia MFC DLL, zaczynają się standardowe zasady dotyczące budowania aplikacji przy użyciu udostępnionych wersji MFC, a następnie wykonaj następujące czynności:

Zmienianie plików nagłówka

Celem rozszerzenia DLL zazwyczaj jest na wywóz niektóre typowe funkcje do jednego lub kilku zgłoszeń, które mogą korzystać z tej funkcji. To definiowania eksportującym klas i funkcje globalne, które są dostępne dla aplikacji klienta.

W tym celu muszą ubezpieczenia, że każda z funkcji Członkowskie oznaczony jako importowania lub eksportowania jako właściwe. To wymaga specjalnej deklaracji: __declspec(dllexport) i __declspec(dllimport). Gdy Twój klasy są używane przez aplikacje klienckie, kolejnooci deklaruje się jako __declspec(dllimport). Rozszerzenie DLL, sam jest budowana, powinien być zadeklarowany jako __declspec(dllexport). Ponadto funkcje muszą być faktycznie wywożonych, tak, aby programy klienckie powiązać je w czasie ładowania.

Aby wyeksportować całą klasę, użyj AFX_EXT_CLASS w definicji klasy. To makro jest zdefiniowana w ramach jako __declspec(dllexport) po _AFXDLL i _AFXEXT jest zdefiniowany, ale zdefiniowane jako __declspec(dllimport) , gdy _AFXEXT nie jest zdefiniowana. _AFXEXT jak opisano powyżej, jest definiowana tylko podczas konstruowania z rozszerzeniem DLL. Na przykład:

klasa AFX_EXT_CLASS CExampleExport: CObject publicznych
{... klasy definicji...}

Nie dokonywał wywozu klasy cały

Czasami można eksportować tylko poszczególnych niezbędne członków swojej klasy. Na przykład, jeśli eksportujesz CDialog-klasy, tylko może wystąpić potrzeba wyeksportowania konstruktora i wywołania DoModal . Można eksportować tych członków przy użyciu bibliotek DLL.DEF pliku, ale można także używać AFX_EXT_CLASS w wiele tak samo na poszczególnych członków, potrzebnych do wywozu.

Na przykład:

 klasa CExampleDialog: CDialog publicz&nych
{
publiczne:
 nbsp; AFX_EXT_CLASS CExampleDialog();
   Int AFX_EXT_CLASS DoModal();
   / / pozostałej części definicji klasy
   .
   .
   .
}

Po wykonaniu tej czynności może uruchomić dodatkowe problem ze względu na fakt, że są już eksportowanie wszystkich członków tej klasy. Przyczyną problemu jest sposób tej pracy makra MFC. Kilka MFC firmy pomocnik makr faktycznie zadeklarować lub definiowania danych członków. W związku z tym członkowie ci danych będzie również konieczne mają być wywożone z biblioteki DLL.

Na przykład makro DECLARE_DYNAMIC jest zdefiniowana w następujący sposób Konstruując biblioteki DLL rozszerzenia:

# define DECLARE_DY&NAMIC(class_name) \
chronione: \
 nbsp; statyczne CRuntimeClass * PASCAL _GetBaseClass(); \
   publiczne: \
   statyczne klasy AFX_DATA CRuntimeClass ## nazwa_klasy; \
   wirtualny CRuntimeClass * GetRuntimeClass() stała; \

Wiersz rozpoczynający się "statyczne AFX_DATA" jest deklarowanie obiektu statycznego wewnątrz sieci klasy. Aby poprawnie wyeksportować tej klasy i uzyskać dostęp do informacji runtime przez klienta.EXE, trzeba wyeksportować ten obiekt statyczny. Ponieważ obiekt statyczny jest zadeklarowany przy pomocy modyfikatora AFX_DATA, można tylko potrzebne do definiowania AFX_DATA się __declspec(dllexport) , Konstruując biblioteki DLL i zdefiniować ją jako __declspec(dllimport) , podczas tworzenia pliku wykonywalnego klienta.

Zgodnie z powyższym opisem, AFX_EXT_CLASS jest już zdefiniowana w ten sposób. Dlatego wystarczy porozumiewają AFX_DATA jest taka sama, jak AFX_EXT_CLASS wokół definicji klasy.

Na przykład:

nbsp;  #undef AFX_DATA
   # define AFX_DATA AFX_EXT_CLASS
   Klasa CExampleView: CView publicznych
   {
     DECLARE_DY&NAMIC()
     / /... klasy definicji...
   };
   #undef AFX_DATA
   # define AFX_DATA

MFC zawsze używa AFX_DATA symbol elementów danych, które definiuje w jego makra, więc ta technika będą działać dla wszystkich takiego scenariuszach. Na przykład będą działać dla DECLARE_MESSAGE_MAP.

Uwaga   Jeśli eksportujesz całej klasy zamiast członków wybranej klasy, członkowie dane statyczne są automatycznie eksportowane.

Tę samą technikę można używać do automatycznego wyeksportowania operatora ekstrakcji CArchive dla klas, które korzystają z makra DECLARE_SERIAL i IMPLEMENT_SERIAL . Eksportować operatora archiwum korekcji deklaracje klas (znajduje się w.H plik) z następującego kodu:

#undef AFX_API
# define AFX_API AFX_EXT_CLASS

lt; tutaj swoje deklaracje klas >

#undef AFX_API
# define AFX_API

Ograniczenia _AFXEXT

Można użyć symbolu pre-processorAFXEXT _ dla bibliotek DLL rozszerzeń, tak długo, jak nie masz wiele warstw bibliotek DLL rozszerzeń. Jeśli masz rozszerzeniem biblioteki dll, które zadzwonić lub czerpią z klas w własne rozszerzenie dll, które następnie wynikają z klas MFC, należy użyć symbolu preprocesora w celu uniknięcia niejednoznaczności.

Problemem jest to, że w Win32, należy jawnie zadeklarować wszystkie dane jako __declspec(dllexport) jeśli mają być wywożone z biblioteki DLL i __declspec(dllimport) , jeżeli ma to być przywożone z biblioteki DLL. Podczas definiowania _AFXEXT, nagłówki MFC upewnij się, że AFX_EXT_CLASS jest poprawnie zdefiniowany.

Jeśli masz wiele warstw, jeden symbol takich jak AFX_EXT_CLASS jest nie wystarczający, ponieważ biblioteka DLL rozszerzenia może być eksportujących nowych klas jak również importowanie innych klas z innym rozszerzeniem DLL. Aby radzić sobie z tym problemem, należy użyć specjalnych symboli pre-processor, która wskazuje, że tworzysz DLL kontra przy użyciu biblioteki DLL. Załóżmy na przykład, dwa rozszerzeniem biblioteki dll, A.DLL i B.DLL. Niektóre klasy A.H i B.H, każdy z nich wyeksportować odpowiednio. B.dll korzysta z klas z A.DLL. Pliki nagłówkowe będzie wyglądać mniej więcej tak:

/ / A.H
#ifdef A_IMPL
 nbsp; # define CLASS_DECL_A __declspec(dllexport)
# else
   # define CLASS_DECL_A __declspec(dllimport)
#E&NDIF

Klasa CLASS_DECL_A CExampleA: CObject publicznych
{... klasy definicji...};

/ / B.H
#ifdef B_IMPL
   # define CLASS_DECL_B __declspec(dllexport)
# else
   # define CLASS_DECL_B __declspec(dllimport)
#ENDIF

Klasa CLASS_DECL_B CExampleB: CExampleA publicznych
{... klasy definicji...}

Gdy A.DLL jest zbudowana, jest zbudowany z /D A_IMPL i gdy B.DLL jest zbudowana, jest zbudowany z /D B_IMPL. Za pomocą oddzielnych symbole dla każdej biblioteki DLL, eksportowany jest CExampleB i CExampleA jest przywożone podczas konstruowania B.DLL. CExampleA jest eksportowany podczas konstruowania A.DLL i przywożone, gdy jest używana przez B.DLL (lub innego klienta).

Ten typ warstwy nie można wykonać, korzystając z wbudowanej AFX_EXT_CLASS i _AFXEXT pre-processor symboli. Technika opisane powyżej rozwiązuje ten problem w sposób nie inaczej niż, mechanizm MFC, sam używa podczas konstruowania rozszerzenie OLE, bazy danych i sieci biblioteki DLL.

Nie dokonywał wywozu klasy cały

Ponownie będą musiały zwrócić szczególną uwagę, kiedy nie eksportujesz całej klasy. Trzeba zapewnić, prawidłowo wyeksportowane elementy niezbędne dane utworzone przez makra MFC. Można to zrobić przez re-defining AFX_DATA do swojej klasy określone makro. Należy to zrobić dowolnym czasie nie eksportujesz całej klasy.

Na przykład:

/ / A.H
#ifdef A_IMPL
 nbsp; # define CLASS_DECL_A _declspec(dllexport)
# else
   # define CLASS_DECL_A _declspec(dllimport)
   #E&NDIF

#undef AFX_DATA
# define AFX_DATA CLASS_DECL_A

Klasa CExampleA: CObject publicznych
{
   DECLARE_DYNAMIC()
   Int CLASS_DECL_A SomeFunction();
   Definicja //Class.
   .
   .
};

#undef AFX_DATA
# define AFX_DATA

DllMain

Oto kod dokładne, którą należy umieścić w pliku głównego źródła dla biblioteki DLL rozszerzenia. Powinna pochodzić po zawiera standardowe. Należy zauważyć, że podczas AppWizard umożliwia tworzenie startowych plików z rozszerzeniem DLL, dostarcza DllMain dla Ciebie.

# include "afxdllx.h"

statyczne AFX_EXTE&NSION_MODULE extensionDLL;

extern "C" int APIENTRY DllMain (wystąpienie HINSTANCE wystąpienie hInstance, DWORD dwReason, elementem LPVOID)
{
 nbsp; Jeżeli (dwReason == DLL_PROCESS_ATTACH)
   {
      / / Jednorazowe Inicjowanie DLL rozszerzenia if (!AfxInitExtensionModule)
             extensionDLL, wystąpienie hInstance))
         zwrócona wartość 0;

/ / TODO: wykonywanie innych zadań inicjowania, tutaj
   }
   else if (dwReason == komunikat DLL_PROCESS_DETACH)
   {
      / / Biblioteka DLL rozszerzenia każdego procesu zakończenia
      AfxTermExtensionModule(extensionDLL);

/ / TODO: wykonywać inne zadania oczyszczania, tutaj
   }
   zwrócona wartość 1;   / / ok
}

Wywołanie AfxInitExtensionModule przechwytuje moduły klas runtime na (CRuntimeClass struktur) jak również fabryk obiektu (COleObjectFactory obiekty) do użytku w przyszłości, kiedy tworzony jest obiekt CDynLinkLibrary . (Opcjonalnie) wywołanie AfxTermExtensionModule umożliwia MFC oczyszczanie Biblioteka DLL rozszerzenia podczas każdego procesu odłącza (co się dzieje, kiedy proces lub jeśli biblioteka DLL jest zwolniona z wywołania FreeLibrary ) z rozszerzeniem DLL. Ponieważ większość rozszerzenie dll nie są załadowane dynamicznie (zwykle one są połączone za pośrednictwem ich bibliotek przywozu), wywołanie AfxTermExtensionModule zazwyczaj nie jest konieczne.

Jeżeli aplikacji ładuje i zwal&nia bibliotek DLL rozszerzeń dynamicznie, pamiętaj wywołać AfxTermExtensionModule jak pokazano above.nbsp; Ponadto należy koniecznie używać AfxLoadLibrary i AfxFreeLibrary (zamiast funkcji Win32 LoadLibrary i FreeLibrary), jeśli dana aplikacja korzysta z wielu wątków. Korzystanie z AfxLoadLibrary i AfxFreeLibrary już, że kod uruchamianiem i zamykaniem systemu, który jest wykonywany, gdy biblioteka DLL rozszerzenia jest załadowane lub wyładowane nie spowodować uszkodzenie globalnego Państwo MFC.

Nagłówek, plik AFXDLLX.H zawiera szczególne definicje dla struktur używany jako rozszerzenie dll, takich jak definicja AFX_EXTENSION_MODULE i CDynLinkLibrary.

Globalne extensionDLL musi być zadeklarowana, jak pokazano. W odróżnieniu od wersji 16-bitowej MFC można przydzielić pamięci i wywoływać funkcje MFC w tym czasie, ponieważ MFCxx.DLL jest w pełni zainicjowany przez czas, który nosi nazwę użytkownika DllMain.

Współużytkowanie zasobów i klasy

Proste MFC DLL rozszerzenia należy eksportować tylko kilka funkcji niskiej przepustowości do aplikacji klienta i nic więcej. Więcej intensywne biblioteki DLL interfejsu użytkownika może chcesz wyeksportować zasobów i C++ klas do aplikacji klienckiej.

Eksportowanie zasobów odbywa się za pośrednictwem listy zasobów. W każdej aplikacji jest pojedynczo połączonej listy obiektów CDynLinkLibrary . Podczas wyszukiwania zasobów, większość standardowych implementacje MFC, że obciążenia zasobów wyszukiwania pierwszego na bieżący moduł zasobów (AfxGetResourceHandle) i jeżeli nie znaleziono spacer listy obiektów CDynLinkLibrary próba załadowania żądanego zasobu.

Dynamiczne tworzenie obiektów języka C++, podać nazwę klasy języka C++ jest podobna. Mechanizm deserializacji obiektu MFC musi mieć wszystkie obiekty CRuntimeClass zarejestrowany tak, że można odtworzyć tworząc dynamicznie C++ obiektu typu wymagane na podstawie co znajdował się wcześniej.

Jeśli chcesz, aby aplikacja klienta do używania klas w Biblioteka DLL rozszerzenia, które są DECLARE_SERIAL, będzie potrzebne do eksport Twojego klas widoczny do aplikacji klienckiej. Robi się to także przez chodzenia na liście CDynLinkLibrary.

W przypadku próbki MFC zaawansowane pojęcia DLLHUSK, listy wygląda mniej więcej następująco

&głowa - BT;   DLLHUSK.EXE - lub DLLHUSK.EXE
               |                      |
          TESTDLL2.BIBLIOTEKA DLL TESTDLL2.BIBLIOTEKA DLL
               |                      |
          TESTDLL1.BIBLIOTEKA DLL TESTDLL1.BIBLIOTEKA DLL
               |                      |
           MFCO42D.DLL                |
               |                      |
           MFCD42D.DLL                |
               |                      |
            MFC42D.BIBLIOTEKA DLL MFC42.BIBLIOTEKA DLL

MFCxx.DLL jest zazwyczaj ostatni na liście klasy i zasobów. MFCxx.DLL zawiera wszystkie standardowe zasobów MFC, w tym monitu ciągi dla wszystkich identyfikatorów standardowe polecenia. Umieszczenie na ogonie listy umożliwia bibliotek DLL i sama aplikacja klienta nie ma własną kopię standardowe zasoby MFC, ale aby polegać zasobów udostępnionych w MFCxx.DLL zamiast.

Scalenie zasobów i nazw klas wszystkich bibliotek DLL w przestrzeni nazw aplikacji klienta ma niekorzystnej sytuacji, który należy uważać co identyfikatory lub nazwy, którą należy wybrać. Aby wyłączyć tę funkcję, można oczywiście nie eksportowanie zasobów lub obiekt CDynLinkLibrary do aplikacji klienckiej. DLLHUSK próbki zarządza przestrzeni nazwa zasobu udostępnionego przy użyciu wielu plików nagłówkowych. Zobacz technicznych 35 Uwaga Aby uzyskać więcej porad na temat używania plików udostępnionych zasobów.

Inicjowanie DLL

Jak wspomniano powyżej, zazwyczaj trzeba utworzyć obiekt CDynLinkLibrary na wywóz środków i klas do aplikacji klienckiej. Konieczne będzie zapewnienie wywożonych wlotu do zainicjowania biblioteki DLL. Minimalny zestaw jest nieważne rutynowych, nie przyjmuje żadnych argumentów i zwraca nic, ale można nadać dowolną.

Każdej aplikacji klienckiej, która chce używać biblioteki DLL musi wywoływać ten inicjacji, jeżeli użyjesz tej metody. Ten obiekt CDynLinkLibrary może przydzielić w Twojej DllMain , tuż po wywołaniu AfxInitExtensionModule.

Inicjacji musi utworzyć obiekt CDynLinkLibrary w bieżącej aplikacji sterty, przewodowe do z rozszerzeniem DLL informacji. Może to być wykonane z następujących:

extern "C" extern void WI&NAPI InitXxxDLL()
{
 nbsp; Nowy CDynLinkLibrary(extensionDLL);
}

Nazwa rutynowych, InitXxxDLL w tym przykładzie może być cokolwiek chcesz. Nie trzeba być extern “C” , ale spowoduje tak czyni łatwiejszy do utrzymania listy wywozu.

Uwaga   Korzystając z biblioteki DLL z regularnych biblioteki DLL rozszerzenia, należy wyeksportować tę funkcję inicjacji. Ta funkcja musi być wywołana z regularnych DLL przed użyciem rozszerzenie DLL klas ani zasobów.

Eksportowanie wpisów

Prostym sposobem eksport Twojego klas jest użycie __declspec(dllimport) i __declspec(dllexport) na każdej klasy i funkcja globalna, który chcesz eksportować. To sprawia, że są to jest znacznie łatwiejsze, ale jest mniej efektywne niż nazewnictwa każdy punkt wejścia (opisanych poniżej), ponieważ ma mniej kontrolę nad eksportowany funkcje i nie można wyeksportować funkcji przez porządkowych. Jest to metoda, że zarówno TESTDLL1, jak i TESTDLL2 umożliwia eksportowanie ich wpisy.

Bardziej efektywną metodą (i metoda używana przez MFCxx.DLL) jest wyeksportowanie każdego wpisu ręcznie nazywając każdego wpisu.DEF pliku. Ponieważ musimy są eksportowane selektywne wywozu z naszej bibliotece DLL (oznacza to, że nie wszystko), możemy zadecydować, które poszczególnych interfejsów chcemy wywozu. Jest to trudne, ponieważ zniekształcone nazwy do linker musi określić w formularzu wpisy.DEF pliku. Nie Eksportuj wszystkich klas języka C++, jeśli naprawdę potrzebujesz mieć łącza symbolicznego dla niego.

Po wypróbowaniu eksportujących C++ klasy z.DEF pliku przed może zaistnieć potrzeba opracowania narzędzia do generowania listy automatycznie. Można to zrobić przy użyciu dwóch etap procesu łącze. Łącze biblioteki DLL raz z wywozu i umożliwiają łączenie do generowania.Plik mapy. .Pliku mapy można wygenerować listę funkcji, które powinny być wywożone, tak z niektórych munging, może służyć do generowania wpisy wywozu dla użytkownika.DEF pliku. Lista wywóz MFCxx.DLL OLE i DLL rozszerzenia bazy danych, kilka tysięcy w polu numer został wygenerowany z takiego procesu (chociaż nie jest całkowicie zautomatyzowany i wymaga niektóre strony dostrajania co raz za chwilę).

CWinApp vs. CDynLinkLibrary

Biblioteka DLL rozszerzenia MFC nie CWinApp-pochodnych obiektu własnych; Zamiast tego należy działać z CWinApp-pochodnych obiektu aplikacji klienta. Oznacza to, że aplikacja kliencka właścicielem pompy głównej wiadomości, pętlę bezczynności itd.

Biblioteki MFC DLL rozszerzenia musi utrzymać dodatkowe dane dla każdej aplikacji, można czerpać nową klasę z CDynLinkLibrary i, należy go utworzyć w InitXxxDLL rutynowe opisano powyżej. Podczas uruchamiania, biblioteka DLL może sprawdzić bieżącej aplikacji listę obiektów CDynLinkLibrary , aby znaleźć jeden dla tego określone rozszerzenie DLL.

Korzystając z zasobów w implementacji biblioteki DLL

Jak wspomniano powyżej, obciążenie zasobów domyślnie pomogą listy obiektów CDynLinkLibrary szuka pierwszej EXE lub DLL, która ma żądanego zasobu. Wszystkie API MFC, jak również wszystkie wewnętrzne kod wykorzystuje AfxFindResourceHandle zaprezentuje listę zasobów w celu znalezienia dowolnego zasobu, niezależnie od tego, gdzie może zamieszkiwać.

Jeśli chcesz tylko obciążenia zasobów z określonego miejsca, za pomocą interfejsów API AfxGetResourceHandle i AfxSetResourceHandle , aby zapisać Stary uchwyt i ustawić nowy uchwyt. Pamiętaj przywrócić starej uchwyt zasobów przed powrócisz do aplikacji klienckiej. Próbki TESTDLL2 wykorzystuje podejście do jawnego ładowania menu.

Chodzenia na liście ma wady jest nieco wolniej i wymaga zarządzania zakresami identyfikator zasobu. Ona ma tę zaletę, że aplikacji klienckiej, która łączy do kilku DLL rozszerzenia można użyć dowolnego zasobu w dostarczonych do biblioteki DLL bez konieczności określania uchwyt wystąpienia biblioteki DLL. AfxFindResourceHandle to API używana do chodzenia na liście zasobów do znajdowania danym meczu. Pobiera nazwę i typ zasobu i zwraca uchwyt zasobów gdzie został po raz pierwszy odnaleziony (lub NULL).

Aplikacja, która używa wersji biblioteki DLL

Wymagania aplikacji

Aplikacja, która używa udostępnioną wersję MFC należy wykonać kilka prostych reguł:

Budynek z środowiska programistycznego

Jeśli używasz wewnętrznego makefile większość standardowych wartości domyślnych, możesz łatwo zmienić projekt budowy wersja biblioteki DLL.

Następującego kroku zakłada się, że masz prawidłowo funkcjonującej aplikacji MFC, połączone z NAFXCWD.LIB (dla debugowania) i NAFXCW.LIB (do sprzedaży detalicznej) i chcesz, aby przekonwertować go do udostępnionej wersji biblioteki MFC. Uruchomiono środowiska Visual C++ i plik Projekt wewnętrzny.

  1. Wybierz ustawienia z Build menu. Na stronie Ogólne w obszarze Ustawienia projektu zestawu Microsoft Foundation Classes do użytku MFC w udostępnionych DLL (MFCxx(d).dll).

Budynek z NUPEWNIJ

Jeśli używasz funkcji zewnętrznych makefile Visual C++ lub bezpośrednio z NUPEWNIJ trzeba edycji Twojego pliku makefile do obsługi kompilatorem i opcje Konsolidator

Wymagana kompilator flagi:

/ D_AFXDLL /MD

/ D_AFXDLL

Standardowych nagłówków MFC potrzebują tego symbolu należy określić:

/MD

Wniosek należy użyć wersji biblioteki DLL biblioteki C-runtime

Wszystkie pozostałe flagi kompilatora wykonaj domyślne MFC (na przykład _DEBUG dla debugowania).

Edytuj listę Konsolidator bibliotek. Zmiana NAFXCWD.LIB do MFCxxD.LIB i zmienić NAFXCW.LIB MFCxx.LIB. Dodaj MFCOxx[U]D.LIB, MFCDxx[U]D.LIB i MFCNxx[U]D.LIB jako właściwe (wymagane w przypadku wykorzystania MFC/OLE, bazy danych lub sieci klasy). Zastąpić LIBC.LIB z MSVCRT.BIBLIOTEKA. Jak z innymi biblioteki MFC jest ważne, że MFCxxD.LIB jest umieszczany przed żadnych bibliotek C-runtime.

Opcjonalnie dodaj /D_AFXDLL do obu sieci detaliczne i debugowania opcje kompilatora zasobu (jeden, który faktycznie kompiluje zasobów z przełącznikiem/r). Dzięki temu użytkownika końcowego wykonywalny mniejszych udostępnianie zasobów, które są obecne w bibliotekach DLL MFC.

Wymagana jest pełna Odbuduj, po dokonaniu tych zmian.

Tworzenie próbek

Większość programów przykładowych MFC może powstać z Visual C++ lub udostępnionych MAKEFILE NUPEWNIJ zgodnego z wiersza polecenia.

Aby przekonwertować dowolny z tych próbek używać MFCxx.DLL, można załadować.MAK pliku do programu 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 i które zbuduje próbki przy użyciu bibliotek MFC.

Próbki MFC zaawansowane pojęcia DLLHUSK jest zbudowany z wersją biblioteki DLL MFC. Próbka ta nie tylko ilustruje sposób budowania aplikacji związanych z MFCxx.DLL, ale ilustruje również inne funkcje opcji opakowania MFC DLL, takich jak MFC DLL rozszerzenia opisanych w dalszej części tego Uwaga techniczna.

Opakowania notatki

Wersja detaliczna biblioteki DLL (MFCxx [U].Biblioteka DLL) są swobodnie redystrybucyjny. Wersja debugowania bibliotek DLL nie są swobodnie redystrybucyjny i powinno być używane tylko podczas opracowywania aplikacji.

Debugowania biblioteki DLL są wyposażone w informacje debugowania. Za pomocą debugera Visual C++, można śledzić wykonanie aplikacji, a także biblioteki DLL. Biblioteki DLL Release (MFCxx [U].Biblioteka DLL) nie zawierają informacje o debugowaniu.

Jeśli dostosować i przebudować biblioteki dll, następnie można zadzwonić je coś innego niż plik "MFCxx" The MFC SRC MFCDLL.MAK opisano opcje kompilacji i zawiera logikę zmiana nazwy biblioteki DLL. Zasada ta stosuje się również do MFC/OLE, bazy danych i sieciowe biblioteki dll, które są budowane przez MFCOLE.MAK, MFCDB.MAK i MFCNET.MAK, odpowiednio. Zmiana nazw plików jest konieczne, ponieważ te biblioteki DLL potencjalnie są współużytkowane przez wiele aplikacji MFC. Posiadające niestandardowej wersji biblioteki MFC DLL Zamień te zainstalowane w danym systemie może przerwać inna aplikacja 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, jak biblioteki MFC DLL (MFCxx.DLL i MFCxxD.DLL) jest zaimplementowana. Zrozumienie, że także tutaj szczegóły nie są ważne, jeśli wszystkie użytkownik chce wykonać jest biblioteki MFC DLL za pomocą aplikacji. Tutaj szczegóły nie są istotne dla zrozumienia jak programować rozszerzenia MFC DLL, ale zrozumienie tej implementacji może pomóc można pisać własne biblioteki DLL.

Przegląd wykonania

Biblioteki MFC DLL naprawdę jest szczególnym przypadkiem Biblioteka DLL rozszerzenia MFC, jak opisano powyżej. Posiada bardzo duża liczba wywozu dla dużej liczby klas. Istnieje kilka dodatkowych rzeczy, które możemy zrobić w bibliotece MFC DLL ułatwiające bardziej specjalne niż regularne Biblioteka DLL rozszerzenia.

Win32 jest większość pracy

16-Bitowa wersja MFC potrzebne szereg szczególnych technik, w tym na aplikacji danych w segmencie stosu specyficzne segmenty utworzone przez niektóre kodu zestawu 80 x 86, na proces wyjątek konteksty i innych technik. Win32 popiera bezpośrednio na proces danych biblioteki DLL, które to, co ma większość czasu. W większości przypadków MFCxx.DLL jest po prostu NAFXCW.LIB pakowane w bibliotece DLL. Jeśli spojrzysz na kod źródłowy MFC, znajdziesz bardzo niewiele #ifdef _AFXDLL, ponieważ są bardzo niewiele przypadków szczególnych, które należy wprowadzić. Przypadki specjalne, które są specjalnie dla przeciwdziałania Win32 w systemie Windows 3.1 (znanych także jako Win32s). Win32s jest nie wsparcia na proces DLL danych bezpośrednio tak biblioteki MFC DLL należy użyć pamięci lokalnej wątku (TLS) Win32 API uzyskiwania danych lokalnych procesów.

Wpływ na bibliotece źródeł, dodatkowe pliki

Wpływ wersji _AFXDLL na normalnej klasy MFC biblioteki źródeł i nagłówki jest stosunkowo niewielkie. Istnieje specjalna wersja pliku (AFXV_DLL.H) jak również dodatkowym nagłówkiem pliku (AFXDLL_.H) zawarte przez głównego AFXWIN.H nagłówka. AFXDLL_.H nagłówek zawiera klasę CDynLinkLibrary i inne szczegóły dotyczące implementacji aplikacji _AFXDLL i MFC DLL rozszerzenia. AFXDLLX.H nagłówka jest przewidziane budowania MFC DLL rozszerzenia (patrz powyżej szczegółów).

Regularne źródeł do biblioteki MFC w MFC SRC mają niektóre dodatkowy kod warunkowego w _AFXDLL #ifdef. Plik dodatkowym źródłem (DLLINIT.CPP) zawiera dodatkowy kod inicjowania biblioteki DLL i innych klej do udostępnionej wersji MFC.

Aby utworzyć udostępnioną wersję MFC, są dostarczane pliki dodatkowe. (Zobacz poniżej szczegółowe informacje dotyczące tworzenia biblioteki DLL.)

Tworzenie biblioteki MFC DLL

Odbudowa biblioteki MFC DLL jest celowo trudne, więc możesz think twice (lub trzykrotnie) przed jego wykonaniem. Jeśli rozumiesz potencjalnych problemów związanych z pakowaniem i redystrybucji ograniczeniami opisanymi poniżej i nadal tak naprawdę potrzeba przebudować biblioteki MFC DLL, możesz.

MFCDLL.MAK pliku zbuduje debugowania biblioteki DLL z CodeView o użytkowniku:

NUPEWNIJ /f mfcdll.mak DEBUG = 1 LIBNAME = MYMFC

MFCDLL.MAK pliku zbuduje DLL wersji bez CodeView o użytkowniku:

NUPEWNIJ /f mfcdll.mak DEBUG = 0 LIBNAME = MYMFC

(podobnie, możesz użyć MFCOLE.MAK, MFCDB.MAK i MFCNET.MAK budować MFCOxxD.DLL, MFCDxxD.DLL i MFCNxxD.DLL--biblioteki dll, które zawierają MFC/OLE, bazy danych i sieci klasy)

Zbuduje prywatnych wersja biblioteki MFC DLL w katalogu MFC SRC z standardowe nazwy MFCxx.DLL i MFCxxD.DLL. Będzie trzeba skopiować je w odpowiednie miejsce na ścieżce do używania nowej biblioteki DLL. MFCDLL.MAK makefile będzie również przebudować biblioteki importu (MFCxx.LIB i MFCxxD.LIB) i umieścić je w katalogu standard MFC LIB. To, zastąpią wbudowane biblioteki MFCxx.LIB i MFCxxD.LIB, więc należy zachować ostrożność,.

Jeśli chcesz rozpowszechnić zmodyfikowaną wersję biblioteki MFC DLL, należy upewnić się, że zmiana nazwy biblioteki DLL w MFCDLL.MAK makefile i dwa.DEF plików. Zobacz makefile MFCDLL.MAK więcej informacji.

Można zmodyfikować bibliotekę i rozpowszechniam sprzedaży detalicznej (/ release) zmodyfikowany biblioteki tylko wtedy, gdy zmienisz na coś innego niż MFCxx.DLL. Użytkownik może nie redystrybuować wersji debugowej albo debugowania zbudowany wbudowane lub niestandardowe biblioteki DLL.

Ograniczenia te redystrybucji są przede wszystkim w celu uniknięcia rozprzestrzeniania niestandardowych i potencjalnie wirusa zawierającej biblioteki DLL. idealnie powinna nie trzeba przebudować biblioteki dll i jeżeli aplikacji można redystrybuować z wbudowanych MFCxx.DLL dostarczane wraz z produktem Visual C++, pozwoli uniknąć wiele problemów dla siebie i użytkownicy.

Zarządzanie pamięcią

Aplikację przy użyciu MFCxx.DLL wykorzystuje wspólny program przydzielania pamięci przez MSVCRTxx.DLL, udostępnionej biblioteki DLL C-runtime. Zarówno aplikacji, wszelkie DLL rozszerzenia, jak również biblioteki MFC DLL, sami, użyj tego programu przydzielania pamięci współdzielonej. Za pomocą udostępnionego DLL dla alokacji pamięci, biblioteki MFC DLL można zaalokować pamięci, który później jest zwolniona przez aplikację lub odwrotnie. Ponieważ zarówno w aplikacji, jak i Biblioteka DLL muszą używać tego samego programu przydzielania, należy nie zastępują C++ globalny operator new lub usunąć operatora. Te same zasady stosuje się do pozostałej części procedur przydzielania pamięci C-runtime (takich jak malloc Odśmiecacz, wolna, itd.).

Liczebniki porządkowe i klasy __declspec(dllexport) oraz biblioteki DLL nazw

Nie używamy class __declspec(dllexport) funkcji kompilator C++. Zamiast tego listy wywozu jest dołączony do źródeł Biblioteka klasy (MFCxx.DEF i MFCxxD.DEF). Eksportowane są tylko te wybierz zestaw punktów wejścia (funkcje i dane). Inne symbole, takie jak MFC prywatnych realizacji funkcji lub klasy, nie są wywożone cały wywóz są wykonywane przez Liczebniki bez nazwy ciągów w tabeli Nazwa rezydentów i nierezydentów .

Za pomocą class __declspec(dllexport) może być alternatywą dla tworzenia mniejszych bibliotek DLL, ale w przypadku o dużej biblioteki DLL jak MFC, domyślne eksportujących mechanizm ma wydajność i pojemność limitów .

Oznacza to wszystkie nowości że możemy pakiet dużą ilość funkcjonalność w wersji MFCxx.DLL, który jest tylko około 800 KB bez narażania znacznie wykonanie lub załadunek szybkością. MFCxx.DLL byłaby 100 K większych miała ta technika nie zostały użyte.To umożliwia także dodać dodatkowy wpis punktów na końcu.DEF pliku umożliwia proste przechowywanie wersji bez pogarszania wydajności prędkości i wielkości wywozu przez porządkowych. Wersja główna korekt w Biblioteka klas MFC zmieni nazwę biblioteki. Oznacza to, że MFC30.Biblioteka DLL jest redystrybucyjny DLL zawierającego wersja 3.0 Biblioteka klas MFC. Uaktualnienie tego pliku dll, powiedzieć, w hipotetyczną 3.1 MFC DLL otrzymałby nazwę MFC31.Biblioteka DLL zamiast. Ponownie zmodyfikowanie kodu źródłowego MFC produkować niestandardową wersję biblioteki MFC DLL, prosimy używać innej nazwy (i najlepiej bez "MFC") w imieniu.

Uwagi techniczne przez liczbę |nbsp; Uwagi techniczne według kategorii

Index