Udostępnij za pośrednictwem


TN033: wersja DLL biblioteki MFC

Uwaga ta opisuje, jak można użyć MFCxx.DLL i MFCxxD.DLL (gdzie x jest numerem wersji MFC) wspólnie z aplikacji MFC i bibliotekami DLL rozszerzeń biblioteki dołączane dynamicznie.Aby uzyskać więcej informacji na temat bibliotek DLL regularnych, zobacz Za pomocą MFC jako część biblioteki DLL.

Ta uwaga techniczna obejmuje trzy aspekty biblioteki dll.Dwa ostatnie są dla bardziej zaawansowanych użytkowników:

  • Jak zbudować Biblioteka DLL rozszerzenia MFC

  • Jak budowanie aplikacji MFC używa wersji biblioteki DLL, biblioteki MFC

  • Jak MFC wspólne biblioteki DLL są implementowane.

Jeśli są Państwo zainteresowani budowanie biblioteki DLL przy użyciu biblioteki MFC, który może być używany z aplikacji innych niż MFC (jest to regularne DLL), zajrzyj do techniczne Uwaga 11.

Omówienie obsługi MFCxx.DLL: terminologii i plików

Regularne DLL: Użyj regularne DLL do tworzenia autonomicznych korzystanie z kilku klas MFC biblioteki DLL.Interfejsy na granicy App/DLL są interfejsy "C", a aplikacja klienta nie ma być aplikacji MFC.

To jest wersja biblioteki DLL obsługi obsługiwane w MFC 1.0.Jest on opisany w techniczne Uwaga 11 i zaawansowane pojęcia MFC próbki DLLScreenCap.

[!UWAGA]

Począwszy od programu 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ż tworzyć regularne biblioteki DLL, która dynamicznie łącza do biblioteki MFC.

MFC 3.0 (lub wyższej) obsługuje regularne bibliotek DLL z nowych funkcji, w tym klasy OLE i bazy danych.

AFXDLL: to jest również nazywane udostępniona wersja biblioteki MFC.Jest to nowy DLL dodano obsługę w MFC 2.0.Samej biblioteki MFC jest w szeregu bibliotek DLL (opisanych poniżej) i dynamicznie łączy biblioteki dll, które wymaga aplikacji klienckiej lub biblioteki DLL.Interfejsy na granicy aplikacji/DLL są C + +/ MFC interfejsu klasy.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]

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

Uwaga ta będzie używana MFCxx.DLL Aby odwołać się do biblioteki MFC DLL zestaw, który zawiera całą:

  • 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 [/ U] [D].LIB biblioteki są używane w połączeniu z MFC współużytkowane biblioteki dll.Te biblioteki zawierają kod, który musi być statycznie powiązana aplikacja lub biblioteka DLL.

Aplikacji łącza do odpowiednich bibliotek importu:

  • Debugowanie: MFCxxD.LIB

  • Wydania: MFCxx.LIB

  • Debugowanie kodu Unicode: MFCxxUD.LIB

  • Wersji Unicode: MFCxxU.LIB

"MFC Biblioteka DLL rozszerzenia" jest biblioteką DLL, zbudowany na MFCxx.DLL (i/lub innych MFC współużytkowane biblioteki dll).W tym miejscu Architektura składników MFC jest uruchamiane.Jeśli pochodzić od klasy przydatne klasy MFC lub innego toolkit MFC-jak budować, należy je umieścić w bibliotece DLL.Że DLL używa MFCxx.DLL, podobnie jak aplikacja kliencka ultimate.Pozwala to na klasy liść wielokrotnego użytku, wielokrotnego użytku klas podstawowych i klas wielokrotnego użytku widoku lub dokumentu.

Wady i zalety

Dlaczego należy użyć udostępniona wersja biblioteki MFC?

  • Korzystanie z udostępnionej biblioteki mogą skutkować mniejszych aplikacji (minimalny aplikacji, która korzysta z biblioteki MFC większości jest mniejsza niż 10K).

  • Udostępniona wersja biblioteki MFC obsługuje biblioteki DLL rozszerzenia MFC i regularne biblioteki dll.

  • Tworzenie aplikacji korzystającej z udostępnianych bibliotek MFC jest szybsze niż budynku statycznie aplikacji MFC, ponieważ nie jest konieczne powiązanie MFC sam.Jest to szczególnie ważne w DEBUG buduje gdzie linker należy kompaktować informacje debugowania — przez powiązanie z biblioteki DLL, która zawiera już informacje o debugowaniu, jest mniej informacji debugowania do kompaktowania w aplikacji.

Dlaczego nie powinno się korzystać udostępniona wersja biblioteki MFC:

  • Wysyłka aplikacji korzystającej z udostępnionej biblioteki wymaga statku MFCxx.DLL (i inne) biblioteki w programie.MFCxx.DLL jest swobodnie do dystrybucji, jak wiele bibliotek DLL, ale nadal należy zainstalować biblioteki DLL w programie Instalatora.Ponadto muszą dostarczać MSVCRTxx.DLL, który zawiera biblioteki C runtime, która jest wykorzystywana zarówno przez program i MFC biblioteki dll, sami.

Jak napisać rozszerzenie MFC DLL

Biblioteka DLL rozszerzenia MFC jest biblioteką DLL, zawierających klasy i funkcje napisane ozdobić funkcjonalność klasy MFC.Biblioteka DLL rozszerzenia MFC używa współużytkowane biblioteki MFC dll w ten sam sposób aplikacja używa go, kilka dodatkowych zagadnień:

  • Proces budowania jest podobna do budowania aplikacji korzystającej z udostępnianych bibliotek MFC z kilku dodatkowych kompilatora i opcje linker.

  • Biblioteka DLL rozszerzenia MFC nie ma CWinApp-klasy.

  • Biblioteka DLL rozszerzenia MFC musi zapewnić specjalne DllMain.Dostarcza AppWizard DllMain funkcji, które można modyfikować.

  • Biblioteka DLL rozszerzenia MFC zapewniają zazwyczaj procedura inicjowania do tworzenia CDynLinkLibrary Jeśli rozszerzenie DLL pragnie wywozić CRuntimeClasses lub zasoby do aplikacji.Pochodna klasy CDynLinkLibrary można stosować, jeśli dane dla aplikacji musi być utrzymana przez rozszerzenie DLL.

Rozważania te są opisane bardziej szczegółowo poniżej.Powinna również dotyczyć przykładowy zaawansowanych koncepcji MFC DLLHUSK ponieważ przedstawia:

  • Budowanie aplikacji za pomocą bibliotek współdzielonych. (DLLHUSK.EXE jest aplikacji MFC, która dynamicznie łączy do bibliotek MFC jak również innych bibliotek DLL).

  • Tworzenia rozszerzeń MFC DLL. (Należy zauważyć specjalne flagi, takich jak _AFXEXT używane w budynku biblioteki DLL rozszerzenia)

  • Dwa przykłady MFC DLL rozszerzenia.Jeden pokazuje podstawową strukturę Biblioteka DLL rozszerzenia MFC z ograniczoną wywozu (TESTDLL1) i inne programy Eksportowanie całej klasy interfejsu (TESTDLL2).

Zarówno aplikacji klienta, jak i wszystkie biblioteki DLL rozszerzenia muszą używać tej samej wersji MFCxx.DLL.Powinno być zgodna z Konwencją MFC DLL i zapewnić zarówno debugowania i handlu detalicznego (/ release) wersja biblioteki DLL rozszerzenia.Pozwala to na programy klienckie do tworzenia i debugowania, jak i detalicznej wersje swoich wniosków i połączyć je z odpowiednich debugowania lub wszystkich plików dll w wersji handlowej.

[!UWAGA]

Ponieważ C++ przekręcona nazwa i eksportować problemy, listy eksportowanych z biblioteki DLL rozszerzenia mogą się różnić między wersjami program debug i sieci sprzedaży tej samej bibliotece DLL i bibliotek DLL dla różnych platform.Handel detaliczny MFCxx.DLL około 2000 wywiezionego punkty wejścia; Program debug MFCxxD.DLL ma około 3000 eksportowane punkty wejścia.

Szybkie notatki na zarządzanie pamięcią

Sekcja zatytułowana "Zarządzanie pamięcią," pod koniec tego Uwaga techniczna opisuje wprowadzanie w życie MFCxx.DLL udostępniona wersja biblioteki MFC.Informacje, które trzeba znać, aby zaimplementować tylko rozszerzenie DLL jest opisane tutaj.

MFCxx.DLL i wszystkich plików DLL rozszerzenia ładowana do przestrzeni adresowej aplikacji klienta będzie używać sam program przydzielania pamięci, ładowania zasobów i innych Państwach "global" MFC tak, jakby były w tej samej aplikacji.Jest to znaczące, ponieważ biblioteki - MFC DLL i regularne biblioteki dll, które statycznie do MFC dokładnym przeciwieństwem i alokowania każdej biblioteki DLL z własnej puli pamięci.

Jeśli biblioteka DLL rozszerzenia przydziela pamięć, że pamięć może swobodnie intermix z żadnym innym obiektem przydzielane przez serwer aplikacji.Ponadto jeśli ulegnie awarii aplikacji korzystającej z udostępnianych bibliotek MFC, ochrony systemu operacyjnego utrzymania integralności innych aplikacji MFC, udostępnianie biblioteki DLL.

Podobnie inne Państwa "global" MFC, jak bieżący plik wykonywalny w celu załadowania zasobów z, są również współużytkowane aplikacji klienta i wszystkie MFC DLL rozszerzenia jak również MFCxx.DLL się.

Budowanie biblioteki DLL rozszerzenia

Służy do tworzenia projektu MFC DLL rozszerzenia AppWizard i automatycznie wygeneruje odpowiednie kompilatora i ustawienia linker.To było również generować DllMain funkcji, które można modyfikować.

Jeśli konwertujesz istniejącego projektu do rozszerzenia MFC DLL rozpoczynać się standardowe zasady dotyczące tworzenia aplikacji za pomocą udostępnionego wersji MFC, a następnie wykonaj następujące czynności:

  • Dodaj /D_AFXEXT do flag kompilatora.W oknie dialogowym właściwości projektu wybierz węzeł C/C++.Następnie wybierz kategorię preprocesora.Dodaj _AFXEXT z polem definiowania makra, oddzielając każdy z elementów średnikami.

  • Usuń /Gy przełącznika kompilatora.W oknie dialogowym właściwości projektu wybierz węzeł C/C++.Następnie wybierz kategorię generowania kodu.Upewnij się, że nie włączono opcję "Włącz łączenie poziom funkcji".Ułatwi do wyeksportowania klas, ponieważ program łączący nie spowoduje usunięcia funkcji bez odwołań.Jeśli oryginalny projekt jest używana do tworzenia regularne biblioteki DLL statycznie połączone z MFC, zmiana /MT [d opcję kompilatora, aby /MD [d.

  • Budowanie biblioteki wywóz z /dll opcji do łącza.Spowoduje to ustawienie podczas tworzenia nowy obiekt docelowy, określanie Win32 biblioteki dołączanej dynamicznie jako typ docelowy.

Zmienianie plików nagłówka

Celem rozszerzenia DLL jest zwykle eksportować niektóre typowe funkcje do jednej lub wielu aplikacji, można użyć tej funkcji.To sprowadza się do eksportujący klasy i funkcje globalne, które są dostępne dla aplikacji klienta.

W tym celu musi upewnić się, że każdy z funkcji elementów członkowskich jest oznaczona jako importowania lub eksportowania odpowiednio.Wymaga to specjalne deklaracje: __declspec(dllexport) i __declspec(dllimport).Podczas swojej klasy są używane przez aplikacje klienckie, mają być zadeklarowany jako __declspec(dllimport).Podczas tworzenia biblioteki DLL, sama rozszerzenia powinien być zadeklarowany jako __declspec(dllexport).Ponadto funkcje muszą zostać faktycznie wywiezione, tak aby programy klienckie powiązać je w czasie ładowania.

Aby wyeksportować całą klasę, należy użyć AFX_EXT_CLASS w definicji klasy.To makro jest zdefiniowany w ramach jako __declspec(dllexport) po _AFXDLL i _AFXEXT jest zdefiniowany, ale zdefiniowane jako __declspec(dllimport) po _AFXEXT nie jest zdefiniowana._AFXEXTjak opisano powyżej, jest definiowana tylko podczas tworzenia biblioteki DLL rozszerzenia.Na przykład:

class AFX_EXT_CLASS CExampleExport : public CObject
{ ... class definition ... };

Nie dokonywał wywozu całej klasy

Czasami można eksportować tylko pojedynczych niezbędnych członków swojej klasy.Na przykład, jeśli eksportujesz CDialog-klasy, może być tylko należy wyeksportować konstruktora i DoModal zadzwonić.Można wyeksportować te elementy przy użyciu biblioteki DLL.Można również użyć rozdzielczości pliku, ale AFX_EXT_CLASS w taki sam 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
   .
   .
   .
};

Gdy to zrobisz, możesz napotkać dodatkowy problem ponieważ już eksportujesz wszystkich członków klasy.Problem jest w taki sposób, że praca makra MFC.Kilka makr pomocnika MFC faktycznie zadeklarować lub definiowania danych członków.W związku z tym członkowie tych danych będzie musiała zostać wywiezione z biblioteki DLL.

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

#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 statycznego obiektu wewnątrz klasy.Poprawnie wyeksportować tej klasy i uzyskać dostęp do informacji runtime z klienta.EXE, należy wyeksportować ten obiekt statyczny.Ponieważ obiekt statyczny jest zadeklarowana z modyfikatorem AFX_DATA, trzeba zdefiniować AFX_DATA za __declspec(dllexport) Konstruując biblioteki DLL i zdefiniować ją jako __declspec(dllimport) podczas tworzenia pliku wykonywalnego klienta.

Jak wspomniano powyżej, AFX_EXT_CLASS jest już zdefiniowana w ten sposób.Po prostu trzeba ponownie zdefiniować AFX_DATA tak samo, jak AFX_EXT_CLASS wokół swojej definicji klasy.

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

Zawsze używa MFC AFX_DATA symbol na elementy danych definiuje w makrach, więc metoda ta będzie działać w przypadku wszystkich takich scenariuszy.Na przykład, będą działać dla DECLARE_MESSAGE_MAP.

[!UWAGA]

Jeśli eksportujesz całej klasy, a nie wybranych elementów członkowskich 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 klas używające DECLARE_SERIAL i IMPLEMENT_SERIAL makra.Eksportuj operator archiwum przez nawiasy w deklaracji klasy (znajdujące 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 symbol preprocesorem dla rozszerzenia tak długo, jak nie masz wiele warstw bibliotek DLL rozszerzeń biblioteki dll.Jeśli mają rozszerzenie biblioteki dll, które zadzwonić lub pochodzić od klasy w własne rozszerzenie bibliotek DLL, które następnie pochodzić od klasy MFC, należy użyć symbolu preprocesora w celu uniknięcia niejednoznaczności.

Problem polega na tym miasto Win32, musi jawnie deklarować, że wszelkie dane jako __declspec(dllexport) Jeśli jest przeznaczony do wywozu z biblioteki DLL, i __declspec(dllimport) w celu zaimportowania z biblioteki DLL.Po zdefiniowaniu _AFXEXT, nagłówki MFC, upewnij się, że AFX_EXT_CLASS jest poprawnie zdefiniowany.

Kiedy masz wiele warstw, jeden symbol takich jak AFX_EXT_CLASS nie jest wystarczające, ponieważ biblioteka DLL rozszerzenia może być eksportowanie nowych klas a także importowanie innych klas z innej biblioteki DLL rozszerzenia.Aby poradzić sobie z tym problemem, należy użyć specjalnych preprocesora symbol, który wskazuje budują DLL porównaniu z wykorzystaniem biblioteki DLL.Załóżmy na przykład, dwa rozszerzenia biblioteki dll, A.DLL i B.DLL.Każdy z nich wyeksportować niektórych klas w A.H i B.H, odpowiednio.B.DLL korzysta z klas z A.DLL.Pliki nagłówków będzie wyglądać mniej więcej tak:

/* 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 A.DLL, jest zbudowany z /D A_IMPL i B.DLL jest zbudowany, jest zbudowany z /D B_IMPL.Za pomocą oddzielnych symbole dla każdej biblioteki DLL, wywożone CExampleB i CExampleA są importowane 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).

Nie można wykonać tego rodzaju warstw, korzystając z 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 bibliotek DLL OLE, bazy danych i sieci.

Nie dokonywał wywozu całej klasy

Ponownie musisz zachować szczególną ostrożność, jeśli nie eksportujesz całej klasy.Musisz zapewnić poprawnie wyeksportować elementy niezbędne dane utworzone przez makra MFC.Można to zrobić przez ponowne definiowanie AFX_DATA do makra z określonej klasy.Należy to zrobić 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

DllMain

Oto dokładny kod, który należy umieścić w pliku głównym źródłem DLL rozszerzeń.Powinna ona po zawiera standardowe.Należy zauważyć, że gdy AppWizard umożliwia tworzenie plików starter DLL rozszerzeń, 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 klas runtime modułów (CRuntimeClass struktur) jak również jego fabryk obiektu (COleObjectFactory obiektów) do użytku późniejszy podczas CDynLinkLibrary tworzony jest obiekt.Wywołanie (opcjonalnie) AfxTermExtensionModule pozwala MFC Oczyszczanie biblioteki DLL rozszerzenia podczas każdego procesu odłącza (co zdarza się, gdy kończy proces lub gdy biblioteka DLL jest wyładowane w rezultacie FreeLibrary call) z biblioteki DLL rozszerzenia.Ponieważ większość rozszerzenie pliki dll nie są ładowane dynamicznie (na ogół są one związane za pośrednictwem swoich bibliotek importu), wywołanie AfxTermExtensionModule zazwyczaj nie jest konieczne.

Jeśli ładuje i zwalnia dynamicznie bibliotek DLL rozszerzeń aplikacji, pamiętaj, aby zadzwonić do AfxTermExtensionModule jak pokazano powyżej.Ponadto należy koniecznie zachować AfxLoadLibrary i AfxFreeLibrary (zamiast funkcji Win32 LoadLibrary i FreeLibrary) Jeśli aplikacja używa wielu wątków lub dynamicznie ładuje biblioteki DLL rozszerzenia.Za pomocą AfxLoadLibrary i AfxFreeLibrary gwarantuje, że kod uruchamiania i zamykania, który wykonuje, gdy biblioteka DLL rozszerzenia jest załadowane lub wyładowane nie doprowadzić do uszkodzenia globalnego MFC.

Nagłówek pliku AFXDLLX.H zawiera szczególne definicje struktur używane w bibliotekach DLL rozszerzenia, takie jak definicja AFX_EXTENSION_MODULE i CDynLinkLibrary.

Globalny extensionDLL musi być zadeklarowany, jak pokazano.W przeciwieństwie do 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 swojej DllMain nazywa się.

Udostępnianie zasobów i klasy

Proste MFC DLL rozszerzenia muszą eksportować tylko kilka funkcji niskiej przepustowości do aplikacji klienta i nic więcej.Więcej intensywne bibliotek DLL interfejsu użytkownika będzie chciał wyeksportować zasobów i klasy języka C++ do aplikacji klienta.

Eksportowanie zasobów odbywa się za pośrednictwem listy zasobów.W każdej aplikacji jest pojedynczo połączonej listy z CDynLinkLibrary obiektów.Gdy szukasz zasobu, większość standardowych implementacje MFC, które ładują zasobów przyjrzeć bieżącego modułu zasobów (AfxGetResourceHandle) i jeżeli nie znaleziono Idź na liście CDynLinkLibrary obiektów próby załadowania żądanego zasobu.

Dynamiczne tworzenie obiektów C++ podana nazwa klasy języka C++ jest podobny.Mechanizm deserializacji obiektu MFC musi mieć wszystkie CRuntimeClass obiektów rejestrowane, dzięki czemu można odtworzyć tworząc dynamicznie obiektu języka C++ jest wymaganego typu oparte na co wcześniej było przechowywane.

Jeśli chcesz, aby aplikacja kliencka użyć klas w DLL rozszerzenia, które są DECLARE_SERIAL, a następnie trzeba będzie wyeksportować sieci klasy mają być widoczne dla aplikacji klienckiej.Jest to również zrobić pieszo CDynLinkLibrary listy.

W przypadku próbki MFC zaawansowane koncepcje DLLHUSK, listy wygląda mniej więcej tak:

head ->   DLLHUSK.EXE   - or -   DLLHUSK.EXE
               |                      |
          TESTDLL2.DLL           TESTDLL2.DLL
               |                      |
          TESTDLL1.DLL           TESTDLL1.DLL
               |                      |
               |                      |
            MFC90D.DLL            MFC90.DLL

MFCxx.DLL jest zazwyczaj w ciągu ostatnich zasobów i listy klas.MFCxx.DLL obejmuje wszystkie standardowe zasobów MFC, w tym wszystkie identyfikatory standardowego polecenia prompt ciągi.Umieszczenie go na końcu listy pozwala bibliotek DLL i aplikacja kliencka nie mieć swoje własne kopie standardowych zasobów MFC, ale aby polegać na zasobach udostępnionych w MFCxx.DLL zamiast.

Scalanie zasobów i nazw klasy wszystkich plików dll w przestrzeni nazw aplikacji klienckiej ma negatywnych skutków, jakie mają być ostrożnym, co identyfikatory lub nazwy, które można wybrać.Można oczywiście wyłączyć tę funkcję nie eksportując albo zasobów lub CDynLinkLibrary obiektu do aplikacji klienta.DLLHUSK próbki zarządza zasobu udostępnionego obszaru nazw przy użyciu wielu plików nagłówkowych.Zobacz technicznej 35 Uwaga uzyskać więcej porad dotyczących używania plików udostępnionych zasobów.

Inicjowanie biblioteki DLL

Jak wspomniano powyżej, zazwyczaj można utworzyć CDynLinkLibrary obiektu, aby eksportować swoje zasoby i klas do aplikacji klienta.Trzeba będzie określić punkt wejścia eksportowanych do zainicjowania biblioteki DLL.Minimalnie jest nieważne rutynowych, który nie przyjmuje żadnych argumentów i nic nie zwraca, ale można go, co tylko chcesz.

Każda aplikacja klienta, który chce korzystać z biblioteki DLL należy wywołać to procedura inicjowania, jeśli użyjesz tej metody.Można także przydzielić to CDynLinkLibrary obiekt w sieci DllMain tylko po wywołaniu AfxInitExtensionModule.

Procedura inicjowania należy utworzyć CDynLinkLibrary obiektu w stosie bieżącej aplikacji, podłączony do sieci rozszerzenie DLL informacji.Można to zrobić z następujących czynności:

extern "C" extern void WINAPI InitXxxDLL()
{
   new CDynLinkLibrary(extensionDLL);
}

Nazwa procedury, InitXxxDLL w tym przykładzie może być dowolną inną.Nie trzeba być extern "C", ale robi tak sprawia, że łatwiejsze do utrzymania listy eksportowanych.

[!UWAGA]

Jeśli używasz rozszerzenie DLL z regularnych biblioteki DLL, należy wyeksportować tej funkcji inicjującej.Ta funkcja musi być wywołana z regularnych biblioteki DLL przed użyciem wszelkich rozszerzenie klasy biblioteki DLL lub zasobów.

Eksportowanie wpisów

Prosty sposób wyeksportować klas jest użycie __declspec(dllimport) i __declspec(dllexport) na każdej klasy i funkcja globalna chcesz eksportować.To sprawia, że o wiele łatwiej, ale mniej skuteczne niż nazewnictwa każdego punktu wejścia (opisanych poniżej), ponieważ masz mniej kontrolę nad jakie funkcje są wywożone, a liczba porządkowa eksportowania funkcje.TESTDLL1 i TESTDLL2 ta metoda umożliwia eksportowanie ich zawartości.

Bardziej efektywną metodą (i metoda używana przez MFCxx.DLL) jest ręcznie wyeksportować każdy wpis przez nadanie mu nazwy każdego wpisu w.Plik DEF.Ponieważ firma Microsoft są eksportowane selektywne wywozu z naszej bibliotece DLL (to znaczy nie wszystko), musimy zdecydować które interfejsy szczególności chcemy, aby eksportować.Jest to trudne, ponieważ zniekształcone nazwy do linker należy określić w formie zapisów.Plik DEF.Nie należy eksportować wszystkich klas języka C++, chyba że naprawdę trzeba mieć łącza symbolicznego.

Jeśli próbowałeś eksportowanie C++ klasy z.DEF plik wcześniej, warto rozwijać narzędzia do automatycznego generowania listy.Można to zrobić za pomocą łączy dwa etapy procesu.Łącze biblioteki DLL raz z wywozu i umożliwić linker do wygenerowania.Plik mapy..Plik mapy można wygenerować listę funkcji, które powinny być wywożone, więc z niektóre zmiany układu, może być używany do generowania wpisy eksportu dla użytkownika.Plik DEF.Listy eksportowanych MFCxx.DLL OLE i biblioteki DLL rozszerzenia bazy danych, kilka tysięcy w polu numer został wygenerowany z takiego procesu (choć nie jest całkowicie zautomatyzowany i wymaga niektóre strony dostrajania raz na jakiś czas).

W porównaniu z CWinApp. CDynLinkLibrary

Biblioteka DLL rozszerzenia MFC nie ma CWinApp-pochodnych obiektu własnych; Zamiast tego musi działać z CWinApp-pochodnych obiektu aplikacji klienta.Oznacza to aplikacja kliencka i tak dalej właścicielem pompy głównej wiadomości, pętlę bezczynności.

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

Korzystanie z zasobów w danej implementacji biblioteki DLL

Jak wspomniano powyżej, obciążenia zasobów domyślne prowadzi wykaz CDynLinkLibrary obiektów poszukuje pierwszy plik EXE lub DLL, która ma żądanego zasobu.Wszystkie interfejsy API MFC, jak również wszystkich używa wewnętrznego kodu AfxFindResourceHandle do walk listę zasobów, aby znaleźć dowolny zasób, bez względu na to, gdzie mogą znajdować się.

Jeśli chcesz załadować tylko zasoby z określonego miejsca użycia interfejsów API AfxGetResourceHandle i AfxSetResourceHandle Aby zapisać stary uchwyt i ustawić nowy uchwyt.Pamiętaj przywrócić stary uchwyt zasobów przed zwróceniem do aplikacji klienckiej.Próbki TESTDLL2 używa tego podejścia do jawnego ładowania menu.

Chodzenie na liście ma wady jest nieco wolniejsze i wymaga zarządzania zakresy identyfikatorów zasobów.Ma tę zaletę, że aplikacji klienckiej, która łączy do kilku bibliotek DLL rozszerzenia można użyć dowolnego zasobu DLL, pod warunkiem bez konieczności określania uchwyt wystąpienia biblioteki DLL.AfxFindResourceHandleInterfejs API służy do chodzenia listy zasobów szukać danego spotkania.Trwa nazwę i typ zasobu i zwraca uchwyt zasobów najpierw stwierdzenia (lub NULL).

Pisania aplikacji, która używa wersji biblioteki DLL

Wymagania aplikacji

Aplikacja używająca udostępniona wersja biblioteki MFC należy wykonać kilka prostych zasad:

  • Musi mieć CWinApp object i obowiązują standardowe reguły pompowania komunikatów.

  • Muszą być skompilowane z zestawem flag kompilatora wymagane (patrz poniżej).

  • Należy go połączyć z biblioteki import MFCxx.Przez ustawienie flagi kompilatora wymagane, nagłówki MFC określają łączenia aplikacji należy połączyć z biblioteki.

  • Aby uruchomić plik wykonywalny, MFCxx.DLL musi być na ścieżce lub w katalogu systemu Windows.

Budowanie z środowiska programistycznego

Jeśli używasz wewnętrznego makefile z największą liczbą standardowe ustawienia domyślne, można łatwo zmienić projekt, aby utworzyć wersję biblioteki DLL.

Następny krok zakłada się, że masz prawidłowego działania aplikacji MFC, połączone z NAFXCWD.Biblioteka (debugowanie) i NAFXCW.Biblioteka (detal) i chcesz przekonwertować go do używania udostępniona wersja biblioteki MFC.Są uruchomione środowisko Visual C++, a projekt wewnętrzny plik.

  1. Na Projekty menu, kliknij przycisk Właściwości.W Ogólne stronie pod Project domyślnie, zestaw Microsoft Foundation Classes MFC wykorzystania w bibliotece DLL udostępnionych (MFCxx(d).dll).

Budowanie z NUPEWNIJ

Jeśli jest używana funkcja zewnętrznego pliku reguł programu make Visual c++ lub pomocą NUPEWNIJ bezpośrednio, konieczne będzie edytowanie pliku makefile do obsługi kompilatora i opcje linker

Wymagane flagi kompilatora:

  • / D_AFXDLL /MD
    / D_AFXDLL

Standardowych nagłówków MFC niezbędne do zdefiniowania tego symbolu:

  • /MD
    Aplikacja musi używać wersji biblioteki DLL biblioteki wykonawczej C

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

Edytuj listę linker bibliotek.Zmiana NAFXCWD.LIB do MFCxxD.LIB i zmienić NAFXCW.LIB do MFCxx.LIB.Zamień LIBC.LIB z MSVCRT.BIBLIOTEKA.Jak z każdej biblioteki MFC jest ważne, że MFCxxD.LIB znajduje się przed żadnych bibliotek C runtime.

Opcjonalnie można dodać /D_AFXDLL zarówno sieci sprzedaży, jak i debugowe opcje kompilatora zasobu (który faktycznie kompiluje zasoby z /r).To sprawia, że Twój plik wykonywalny końcowego mniejsze dzięki udostępnieniu zasobów, które są obecne w biblioteki MFC DLL.

Po tych zmian pełnej przebudowy jest wymagane.

Tworzenie próbek

Większość MFC przykładowe programy mogą być budowane z Visual C++ lub z udostępnionego pliku MAKEFILE NUPEWNIJ zgodnego z wiersza polecenia.

Aby przekonwertować żadnego z tych próbek używać MFCxx.DLL, można załadować.Klucz aktywacji Wielokrotnej plików na kod Visual C++ i ustawianie opcji 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 udostępnianych bibliotek MFC.

Przykładowy zaawansowanych koncepcji MFC DLLHUSK jest zbudowany z wersji biblioteki DLL, biblioteki MFC.Próbka ta nie tylko ilustruje sposób budowania aplikacji związanych z MFCxx.DLL, ale również ilustruje inne funkcje biblioteki MFC DLL opakowania opcji takich jak MFC DLL rozszerzenia opisane w dalszej części tego Uwaga techniczna.

Opakowania notatek

Wersja detaliczna bibliotek DLL (MFCxx [N].Biblioteka DLL) są swobodnie do dystrybucji.Wersja debugowania bibliotek DLL nie są swobodnie do dystrybucji i stosuje się tylko w trakcie opracowywania aplikacji.

Debugowania biblioteki DLL są udostępnione informacje debugowania.Za pomocą debugera Visual C++, można śledzić wykonywanie aplikacji, a także biblioteki DLL.Wersji bibliotek DLL (MFCxx [N].Biblioteka DLL) nie zawierają informacji o debugowaniu.

Jeśli dostosować i przebudować biblioteki dll, następnie można nazwać je coś innego niż plik "MFCxx" The SRC MFC MFCDLL.Klucz aktywacji Wielokrotnej opisuje opcje budowania i zawiera logikę w celu zmiany nazwy pliku DLL.Zmienianie nazw plików jest konieczne, ponieważ tych bibliotek DLL potencjalnie są współużytkowane przez wiele aplikacji MFC.O niestandardowej wersji biblioteki MFC DLL zamiany tych zainstalowanych w systemie przerwanie współużytkowane biblioteki MFC DLL za pomocą innej aplikacji MFC.

Przebudowywanie 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 wszystko, co chcesz robić jest biblioteki MFC DLL za pomocą aplikacji.Szczegółowe informacje nie są istotne dla zrozumienia, jak napisać rozszerzenie MFC DLL, ale opis tej implementacji może pomóc pisać własne biblioteki DLL.

Omówienie wdrażania

Biblioteki MFC DLL jest naprawdę szczególny przypadek Biblioteka DLL rozszerzenia MFC, jak opisano powyżej.Ma bardzo dużą liczbę wywozu dużej liczby klas.Istnieje kilka dodatkowych czynności, co robimy w bibliotece MFC DLL stał się jeszcze bardziej wyjątkowy niż regularne Biblioteka DLL rozszerzenia.

Większość pracy czy Win32

Wersji 16-bitowej biblioteki MFC potrzebna liczba specjalne techniki, łącznie z danymi-app w segmencie stos specjalnych segmentów utworzonych przez jakiś kod zestawu 80 x 86, konteksty wyjątku na proces i innych technik.Win32 bezpośrednio obsługuje dane na proces w bibliotece DLL, która jest, co ma 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 spojrzeć na kod źródłowy MFC, znajdziesz bardzo niewiele _AFXDLL #ifdef, ponieważ istnieje niewielu przypadków szczególnych, które muszą być wykonane.Przypadków szczególnych, które są specjalnie do czynienia z 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 wersja na normalne źródeł biblioteki klas MFC i nagłówków jest stosunkowo niewielki.Istnieje specjalna wersja pliku (AFXV_DLL.H), a także plik dodatkowym nagłówkiem (AFXDLL_.H) zawarte przez głównego AFXWIN.H nagłówka.AFXDLL_.Zawiera nagłówek H CDynLinkLibrary klasy i inne szczegóły dotyczące implementacji obu _AFXDLL aplikacji i biblioteki DLL rozszerzenia MFC.AFXDLLX.H nagłówka jest przewidziane budowanie biblioteki DLL rozszerzenia MFC (zobacz powyżej szczegółowe informacje).

Regularne źródeł do biblioteki MFC w MFC SRC mają niektóre dodatkowy kod warunkowe pod _AFXDLL #ifdef.Pliku dodatkowe źródła (DLLINIT.CPP) zawiera dodatkowy kod inicjujący DLL i innych klej do udostępniona wersja biblioteki MFC.

W celu stworzenia udostępniona wersja biblioteki MFC, znajdują się dodatkowe pliki. (Zobacz poniżej szczegółowe informacje na temat sposobu tworzenia pliku DLL.)

  • Dwa.Pliki DEF są używane do eksportowania biblioteki MFC DLL punkty wejścia dla debugowania (MFCxxD.DEF) i biblioteki DLL wersji (MFCxx.DEF).

  • Osoba.Plik RC (MFCDLL.RC) zawiera wszystkie standardowe zasoby MFC i zasób VERSIONINFO dla biblioteki DLL.

  • A.Plik CLW (MFCDLL.CLW) jest przewidziane, aby umożliwić przeglądanie MFC klasy przy użyciu ClassWizard.Uwaga: Ta funkcja nie jest charakterystyczne dla wersji biblioteki DLL, biblioteki MFC.

Zarządzanie pamięcią

Aplikacja za pomocą MFCxx.DLL używa wspólnego programu przydzielania pamięci dostarczonych przez MSVCRTxx.DLL, udostępnionych DLL C runtime.Aplikacji, wszystkie pliki DLL rozszerzenia i dobrze jako biblioteki MFC dll, same służy to przydzielania pamięci współużytkowanej.Za pomocą alokacji pamięci udostępnionej biblioteki DLL, biblioteki MFC DLL można zaalokować pamięci, która później jest zwolniona przez aplikację lub odwrotnie.Ponieważ zarówno aplikacji, jak i Biblioteka DLL muszą używać samego programu przydzielania, nie powinny zastępować C++ global operator new lub operator delete.Te same zasady stosują się do pozostałej części procedur alokacji pamięci w czasie wykonywania C (takie jak malloc, realloc, wolnegoi innych).

Liczebniki porządkowe i klasy __declspec(dllexport) i nazywanie DLL

Nie używamy class**__declspec(dllexport)** funkcje kompilatora języka C++. Zamiast tego wykaz wywozu jest dołączany źródeł Biblioteka 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 nazwy ciągów w tabeli nazw rezydenta lub nierezydentów.

Za pomocą class**__declspec(dllexport)** może być alternatywą dla budowania mniejszych bibliotek DLL, ale w przypadku dużych DLL jak MFC, domyślne eksportowanie mechanizm ma wydajność i pojemność limitów. 

Co oznacza to wszystkie jest że mamy pakiet dużą ilość funkcji w wersji MFCxx.DLL, który jest tylko około 800 KB bez narażania wiele wykonanie lub szybkość ładowania.MFCxx.DLL byłby 100K większych ta technika nie były używane.To również pozwala na dodawanie punktów dodatkowy zapis na koniec.Plik DEF zezwalająca na proste przechowywanie wersji bez naruszania skuteczności szybkości i wielkości wywozu przez porządkowych.Główna wersja poprawki dostępne w bibliotece klas MFC zmieni nazwę biblioteki.Oznacza to, MFC30.DLL jest do dystrybucji pliku DLL zawierającego bibliotekę klas MFC w wersji 3.0.Uaktualnienie tego pliku dll, powiedzieć, w hipotetyczny 3.1 MFC, biblioteka DLL zostanie nadana nazwa MFC31.DLL w zamian.Ponownie zmodyfikowanie kodu źródłowego MFC do produkcji niestandardową wersję biblioteki MFC DLL używać innej nazwy (i najlepiej bez "MFC" w nazwie).

Zobacz też

Inne zasoby

Uwagi techniczne według numerów

Uwagi techniczne według kategorii