TN033: DLL verze knihovny MFC

Tato poznámka popisuje, jak lze použít MFCxx.DLL a MFCxxD.DLL (kde x je číslo verze knihovny MFC) sdílené knihovny DLL s aplikací knihovny MFC a knihovny DLL rozšíření.Další informace o běžné knihovny DLL, viz Použití knihovny MFC jako součást knihovny DLL.

Tato technická Poznámka zahrnuje tři aspekty knihoven DLL.Poslední dva jsou určeny pro pokročilé uživatele:

  • Jak vytvářet knihovny MFC příponu DLL.

  • Jak vytvářet aplikace knihovny MFC, která používá DLL verze knihovny MFC

  • Sdílení knihovny MFC knihovny DLL jsou implementovány.

Pokud máte zájem o vytvoření knihovny DLL pomocí knihovny MFC, který lze použít s aplikacemi non-MFC (to se nazývá obvyklá knihovna DLL), podívejte se Technická poznámka: 11.

Přehled podpory MFCxx.DLL: terminologie a soubory

Běžné knihovny DLL: použít běžnou DLL Knihovnu vytvořit samostatné používání některých tříd MFC knihovny DLL.Rozhraní přes hranice aplikace nebo knihovna DLL jsou rozhraní "C" a klientské aplikace nemusí být aplikací knihovny MFC.

Toto je verze DLL podporovat podporovaný v MFC verze 1.0.Je popsán v Technická poznámka: 11 a pokročilé koncepty MFC ukázkové DLLScreenCap.

[!POZNÁMKA]

Stejně jako Visual C++ verze 4.0 pojem USRDLL je zastaralá a byla nahrazena běžnou DLL Knihovnu, která je staticky propojena ke knihovně MFC.Může také vytvořit běžné knihovny DLL, která dynamicky propojuje ke knihovně MFC.

MFC 3.0 (a vyšší) podporuje běžné knihovny DLL s novými funkcemi včetně třídy OLE a databáze.

AFXDLL: to jsou také označovány jako sdílenou verzi knihovny MFC.To je nové knihovny DLL byla přidána podpora v MFC verze 2.0.Klientské aplikace nebo knihovna DLL dynamicky propojuje knihovny DLL, které vyžaduje samotné knihovny MFC je v řadě knihoven DLL (popsáno níže).Rozhraní přes hranice aplikace nebo knihovna DLL jsou C + +/ rozhraní třídy knihovny MFC.Klientská aplikace musí být aplikací knihovny MFC.To podporuje všechny funkce knihovny MFC 3.0 (výjimka: UNICODE není podporován pro databázové třídy).

[!POZNÁMKA]

Od Visual C++ verze 4.0 Tento typ knihovny DLL je označována jako "Rozšiřující knihovna DLL."

Tato poznámka bude používat MFCxx.DLL odkázat na celé sady MFC DLL, která obsahuje:

  • Ladění: MFCxxD.DLL (kombinované) a MFCSxxD.LIB (statické).

  • Vydání: MFCxx.DLL (kombinované) a MFCSxx.LIB (statické).

  • Ladění kódu Unicode: MFCxxUD.DLL (kombinované) a MFCSxxD.LIB (statické).

  • Verze Unicode: MFCxxU.DLL (kombinované) a MFCSxxU.LIB (statické).

[!POZNÁMKA]

MFCSxx [U] [D].LIB knihovny se používají ve spojení s knihovny MFC sdílené knihovny DLL.Tyto knihovny obsahují kód, který musí být aplikace nebo knihovna DLL staticky propojeny.

Odkazy aplikace na odpovídající knihovny importu:

  • Ladění: MFCxxD.LIB

  • Verze: MFCxx.LIB

  • Ladění kódu Unicode: MFCxxUD.LIB

  • Unicode verze: MFCxxU.LIB

"Knihovna MFC příponu DLL" je DLL Knihovna MFCxx.DLL postavena (nebo jiné knihovny MFC sdílené knihovny DLL).Zde architektura komponenty knihovny MFC dojde.Pokud užitečné třídy jsou odvozeny od třídy knihovny MFC, nebo vytvořit jiné podobné MFC toolkit, umístěte jej v knihovně DLL.Knihovny DLL používané v MFCxx.DLL, stejně jako ultimate klientské aplikace.To umožňuje opakovaně list třídy, opakovaně základní třídy a třídy opakovaně zobrazení/dokumentů.

Výhody a nevýhody

Proč používat sdílenou verzi knihovny MFC?

  • Použití sdílené knihovny může mít za následek menší aplikace (minimální aplikace, která používá většina knihovny MFC je menší než 10 kB).

  • Sdílená verze knihovny MFC podporuje DLL rozšíření standardu MFC a běžné knihovny DLL.

  • Vytvoření aplikace, která používá sdílené knihovny MFC je rychlejší než sestavování staticky propojené aplikace knihovny MFC, protože není nutné propojí knihovnu MFC sama.To platí zejména v ladění sestavení, kde musí propojovací program kompaktně ladit informace – o propojení s knihovnou DLL, která již obsahuje informace o ladění, je méně ladící informace ke spojení v rámci aplikace.

Proč by neměly používat sdílenou verzi knihovny MFC:

  • Expediční aplikace, která používá sdílené knihovny vyžaduje dodání MFCxx.DLL (a dalších) knihovny s vaší aplikací.Knihovna MFCxx.DLL je volně Redistribuovatelná jako mnoho knihoven DLL, ale stále je nutné nainstalovat knihovny DLL instalačního programu.Kromě toho je třeba nabízet MSVCRTxx.DLL, který obsahuje knihovnu C runtime, který se používá jak programu tak samotnými knihovnami MFC DLL.

Jak psát rozšiřující DLL knihovna typu MFC

Knihovna MFC příponu DLL je knihovna DLL obsahující třídy a funkce zápisu na tomto funkcí třídy knihovny MFC.Rozšiřující knihovna DLL MFC používá sdílené knihovny DLL MFC stejným způsobem, jakým aplikace používá, s několika další požadavky:

  • Proces sestavení je podobná vytváření aplikace, která používá sdílené knihovny MFC s několika dalších kompilátoru a možnosti propojovacího programu.

  • Rozšiřující knihovna DLL MFC nemá CWinApp-odvozené třídy.

  • Knihovna MFC příponu DLL musí poskytnout zvláštní DllMain.Dodává AppWizard DllMain funkce, které lze změnit.

  • Rozšiřující knihovna DLL MFC bude dosahovat inicializace vytvořit CDynLinkLibrary Pokud příponu DLL chce exportovat CRuntimeClasses nebo prostředky do aplikace.Odvozenou třídu CDynLinkLibrary mohou být použity, pokud jednotlivé aplikace data musí být udržovány v rozšiřující DLL Knihovně.

Tyto úvahy jsou popsány podrobněji níže.Rovněž naleznete v příkladu MFC Upřesnit pojmy DLLHUSK od ilustruje:

  • Vytváření aplikace pomocí sdílené knihovny. (DLLHUSK.EXE je aplikace knihovny MFC, která je dynamicky propojena do knihovny MFC DLL, stejně jako ostatní).

  • Sestavování rozšířující knihovny MFC DLL. (Poznámka: zvláštní příznaky, jako _AFXEXT používané při vytváření rozšiřující knihovny DLL)

  • Dva příklady DLL rozšíření standardu MFC.Jeden zobrazuje základní strukturu knihovny MFC DLL rozšíření s omezené vývozy (TESTDLL1) a ostatní pořady export celou třídu rozhraní (TESTDLL2).

Klientské aplikace a všechny rozšiřující DLL knihovny musí používat stejnou verzi MFCxx.DLL.By podle úmluvy MFC DLL a poskytují i ladění a maloobchodní (/ release) verze knihovny DLL rozšíření.To umožňuje klientským programům sestavení ladění a maloobchodní verze svých aplikací a jejich propojení s odpovídající ladění nebo prodejní verzi všech knihoven DLL.

[!POZNÁMKA]

Vzhledem k tomu, že C++ název pozměnění a exportovat problémy, exportovat seznam z rozšiřující knihovny DLL mohou lišit mezi ladění a maloobchodní verze stejné DLL knihovny a knihovny DLL pro různé platformy.Knihovna MFCxx.DLL maloobchodní má asi 2000 exportovaných vstupních bodů; ladění MFCxxD.DLL má přibližně 3000 exportovaných vstupních bodů.

Rychlé poznámky na Správa paměti

V části "Správa paměti," téměř na konci této technické poznámky popisuje provádění MFCxx.DLL sdílenou verzi knihovny MFC.Informace, které potřebujete provádět pouze rozšiřující knihovny DLL je zde popsáno.

Knihovna MFCxx.DLL a všechny rozšiřující DLL knihovny načtené do adresového prostoru klientské aplikace budou používat stejnou přidělenou paměť, načítání prostředku a jiné stavy knihovny MFC "globální" jako kdyby byly ve stejné aplikaci.To je důležité, protože knihovny non - MFC DLL a běžných DLL knihovnách, které jsou staticky propojeny ke knihovně MFC dělají přesný opak a mít každý DLL Knihovnu přidělenou mimo svůj vlastní fond paměti.

Pokud je rozšiřující DLL knihovna přiděluje paměť, pak že paměť můžete libovolně kombinovat s kterýmkoli jiným objektem přidělené aplikace.Také pokud dojde k chybě aplikace, která používá sdílené knihovny MFC, ochranu operačního systému zachovat integritu jakékoliv MFC aplikace sdílení knihovny DLL.

Podobně jiné "globální" stavy knihovny MFC, jako je aktuální spustitelný soubor načíst prostředky, budou sdíleny také mezi klientskou aplikací a všechny DLL rozšíření standardu MFC, stejně jako Knihovna MFCxx.DLL sám.

Vytváření rozšiřující knihovny DLL

Můžete použít k vytvoření projektu MFC DLL rozšíření AppWizard a automaticky vygeneruje příslušný kompilátor a linker nastavení.Byla také generovat DllMain funkce, které lze změnit.

Před převodem existujícího projektu do rozšiřující DLL knihovna typu MFC, začínají standardních pravidel pro vytváření aplikace pomocí sdílenou verzi knihovny MFC a potom proveďte následující kroky:

  • Přidat /D_AFXEXT k příznakům kompilátoru.V dialogovém okně Vlastnosti projektu vyberte uzel C/C++.Vyberte kategorii preprocesoru.Přidat _AFXEXT makra definovat pole, oddělte jednotlivé položky středníkem.

  • Odebrat /Gy přepínače kompilátoru.V dialogovém okně Vlastnosti projektu vyberte uzel C/C++.Vyberte kategorii pro generování kódu.Ujistěte se, že není povolena možnost "Povolit funkce úroveň propojení".To bude jednodušší pro exportování tříd, protože propojovací program neodstraní, na které neexistuje odkaz funkce.Pokud původní projekt je použit k vytvoření běžné knihovny DLL staticky propojené ke knihovně MFC, změna /MT [d možnosti kompilátoru /MD [d.

  • Sestavení knihovny exportu se /DLL možnost propojení.To bude nastaveno vytvoříte nový cíl, zadáním cílového typu Win32 knihovny DLL.

Změna záhlaví souborů

Cílem rozšíření knihovny DLL je obvykle některé běžné funkce Export do jedné nebo více aplikací, které můžete použít tuto funkci.To boils k exportování tříd a globální funkce, které jsou k dispozici pro klientské aplikace.

Za tímto účelem musí zajistit, že každé členské funkce je označena jako importovat nebo exportovat podle potřeby.To vyžaduje zvláštní prohlášení: __declspec(dllexport) a __declspec(dllimport).Při vašich tříd používají klientské aplikace, můžete je deklarovat jako __declspec(dllimport).Při vytváření rozšiřující knihovny DLL, sám by měl být deklarován jako __declspec(dllexport).Kromě toho funkce musí být skutečně vyvezeno, tak, aby programy klienta je svázat v okamžiku načtení.

Chcete-li exportovat celou třídu, použijte AFX_EXT_CLASS v definici třídy.Toto makro je definováno v rámci jako __declspec(dllexport) při _AFXDLL a _AFXEXT je definována, ale definován jako __declspec(dllimport) při _AFXEXT není definována._AFXEXTjak je popsáno výše, pouze je definován při vytváření knihovny DLL rozšíření.Příklad:

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

Neexportování celé třídy

Někdy můžete chtít exportovat pouze jednotlivé nezbytné členy vaší třídy.Například pokud exportujete třídu odvozenou od CDialog, můžete potřebovat exportovat pouze konstruktor a volání DoModal.Tyto členy pomocí knihovny DLL, můžete exportovat.DEF souborů, ale můžete také použít AFX_EXT_CLASS stejným způsobem u jednotlivých členů, které potřebujete exportovat.

Příklad:

class CExampleDialog : public CDialog
{
public:
   AFX_EXT_CLASS CExampleDialog();
   AFX_EXT_CLASS int DoModal();
   // rest of class definition
   .
   .
   .
};

Když toto provedete, můžete se dostat do další problém protože již neexportujete všechny členy třídy.Problém je ve způsobu práce maker knihovny MFC.Několik podpůrných maker knihovny MFC ve skutečnosti deklaruje nebo definuje datové členy.Proto tyto datové členy bude rovněž nutné být exportovány z knihovny DLL.

Například makro DECLARE_DYNAMIC je definováno takto při vytváření rozšiřující knihovny DLL:

#define DECLARE_DYNAMIC(class_name) \
protected: \
   static CRuntimeClass* PASCAL _GetBaseClass(); \
   public: \
   static AFX_DATA CRuntimeClass class##class_name; \
   virtual CRuntimeClass* GetRuntimeClass() const; \

Řádek, který začíná "statické AFX_DATA" je deklarování statického objektu uvnitř vaší třídy.Správné exportování této třídy a přístup k informacím modulu runtime z klienta.EXE, je nutné exportovat tento statický objekt.Protože je statický objekt deklarován s modifikátorem AFX_DATA, potřebujete pouze definovat AFX_DATA na __declspec(dllexport), při sestavování vaší knihovny DLL, a definovat jej jako __declspec(dllimport), při sestavování vašeho klientského spustitelného souboru.

Jak již bylo uvedeno výše, AFX_EXT_CLASS tímto způsobem je již definován.Stačí znovu definovat AFX_DATA stejné jako AFX_EXT_CLASS kolem definice vaší třídy.

Příklad:

   #undef  AFX_DATA
   #define AFX_DATA AFX_EXT_CLASS
   class CExampleView : public CView
   {
     DECLARE_DYNAMIC()
     // ... class definition ...
   };
   #undef  AFX_DATA
   #define AFX_DATA

Knihovna MFC vždy používá AFX_DATA symbol na datových položkách, které definuje v rámci jejích maker, aby tento postup fungoval u všech scénářů.Například bude pracovat pro DECLARE_MESSAGE_MAP.

[!POZNÁMKA]

Chcete-li exportovat celou třídu, nikoli pouze vybrané členy dané třídy, jsou statické datové členy automaticky exportovány.

Stejný postup můžete automaticky exportovat CArchive extrakce operátor pro třídy, které používají DECLARE_SERIAL a IMPLEMENT_SERIAL makra.Exportovat pomocí "bracketing" deklarace tříd operátor archivu (umístěné v.Soubor H) s následujícím kódem:

#undef AFX_API
#define AFX_API AFX_EXT_CLASS

<your class declarations here>

#undef AFX_API
#define AFX_API

Omezení _AFXEXT

Lze použít _AFXEXT symbol před procesoru pro vaše rozšiřující knihovny DLL, pokud nemáte více vrstev rozšiřujících knihoven DLL.Máte-li rozšiřující knihovny DLL, které volají nebo jsou odvozeny od tříd ve vaší vlastní rozšiřující knihovně DLL, která je potom odvozena od tříd knihovny MFC, je nutné se vyhnout dvojznačnosti použitím vašeho vlastního symbolu preprocesoru.

Problém je, že ve Win32 musíte explicitně deklarovat všechna data jako __declspec(dllexport) pokud mají být exportovány z knihovny DLL a __declspec(dllimport) pokud mají být importovány z knihovny DLL.Když nadefinujete _AFXEXT, hlavičky knihovny MFC se ujistí, že je správně definován AFX_EXT_CLASS.

Pokud máte více vrstev, jeden symbol, jako AFX_EXT_CLASS nestačí, protože rozšiřující knihovna DLL může exportovat nové třídy, stejně jako importovat jiné třídy z jiné rozšiřující knihovny DLL.Při řešení tohoto problému, použijte speciální symbol preprocesoru, který označuje, že vytváříte samotnou knihovnu DLL proti používání dané knihovny DLL.Představte si například dvě rozšiřující knihovny DLL, A.DLL a B.DLL.Každá exportuje některé třídy v A.H B.H..B.DLL používá třídy z A.DLL.Soubory hlaviček by vypadaly přibližně takto:

/* 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 .. };

Při vytváření A.DLL je sestavena s /D A_IMPL a při vytváření B.DLL je sestavena s /D B_IMPL.Použitím oddělených symbolů pro každou knihovnu DLL CExampleB exportována a importována CExampleA při vytváření B.DLL.CExampleA je exportována při vytváření A.DLL a importována při použití B.DLL (nebo jiného klienta).

Tento typ vrstvení nelze provést s použitím vestavěné AFX_EXT_CLASS a _AFXEXT symboly preprocesoru.Technika popsaná výše řeší tento problém způsobem ne nepodobným mechanismu sama knihovna MFC používá při vytváření rozšiřující knihovny DLL, která jeho OLE databáze a sítě.

Neexportování celé třídy

Opět je třeba věnovat zvláštní pozornost, když neexportujete celou třídu.Je nutné zajistit, že údaje nezbytné položky vytvořené pomocí maker knihovny MFC jsou exportovány správně.To lze provést tím, že znovu definujete AFX_DATA na makro vaší konkrétní třídy.Toto by mělo být provedeno kdykoli, když neexportujete celou třídu.

Příklad:

// 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

Následuje přesný kód, který byste měli umístit do hlavní zdrojový soubor pro vaše rozšiřující knihovny DLL.Vycházela po zahrnuje standardní.Všimněte si, že když pomocí AppWizard vytvořit počáteční soubory rozšiřující knihovny DLL, dodává DllMain pro vás.

#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
}

Volání AfxInitExtensionModule zachytává modulů runtime třídy (CRuntimeClass struktur) stejně jako jeho "továrny objektu" (COleObjectFactory objekty) pro použití při pozdější CDynLinkLibrary je vytvořen objekt.Volání (nepovinné) AfxTermExtensionModule umožňuje knihovně MFC k vyčištění rozšíření DLL při každém odpojení procesu (který se stane při ukončení procesu, nebo pokud knihovna DLL uvolněna z FreeLibrary volání) z rozšiřující knihovny DLL.Protože většina rozšíření nejsou dynamicky načtené knihovny DLL (obvykle jsou propojeny prostřednictvím jejich importy knihoven), volání AfxTermExtensionModule je obvykle nezbytné.

Pokud aplikace načítá a uvolňuje rozšiřující knihovny DLL dynamicky, je nutné volat AfxTermExtensionModule jak je uvedeno výše.Je také nutné používat AfxLoadLibrary a AfxFreeLibrary (namísto funkce Win32 LoadLibrary a FreeLibrary) Pokud aplikace používá více vláken, nebo pokud je rozšiřující knihovna DLL dynamicky načítá.Pomocí AfxLoadLibrary a AfxFreeLibrary zajistí, že kód při spuštění a ukončení, který spustí, pokud rozšiřující knihovna DLL načtena a uvolněna, nepoškozuje globální stav knihovny MFC.

Záhlaví souboru AFXDLLX.H obsahuje zvláštní definice pro struktury používané v rozšířených knihovnách DLL, jako je například definice pro AFX_EXTENSION_MODULE a CDynLinkLibrary.

Globální extensionDLL musí být deklarován, jak je znázorněno.Na rozdíl od 16bitové verze knihovny MFC, můžete přidělit paměť a volat funkce knihovny MFC v průběhu této doby, protože MFCxx.DLL je plně inicializován v době vaší DllMain se nazývá.

Sdílení prostředků a tříd

Jednoduchý DLL rozšíření standardu MFC potřebovat exportovat pouze několik funkcí nízkorychlostní klientské aplikace a nic víc.Další intenzivní DLL uživatelského rozhraní může chcete exportovat zdrojů a třídy jazyka C++ do klientské aplikace.

Export prostředků je realizován prostřednictvím seznamu prostředků.V každé žádosti je jednotlivě propojený seznam CDynLinkLibrary objekty.Při hledání prostředku, většina standardních implementací knihovny MFC, které načítají prostředky, nejprve vyhledává v aktuálním modulu prostředků (AfxGetResourceHandle) a pokud nebylo nalezeno procházení seznamu CDynLinkLibrary objektů k pokusu načíst požadovaný prostředek.

Dynamické vytvoření objektů C++ uveden název třídy C++ je podobné.Mechanismus deserializace objektu knihovny MFC potřebuje mít všechny CRuntimeClass registrované objekty tak, aby jej mohl obnovit dynamickým vytvořením objektů jazyka C++ z požadovaného typu, založeném na co bylo uloženo dříve.

Pokud chcete, aby klientské aplikace pro použití tříd ve vaší rozšiřující knihovně DLL, které jsou DECLARE_SERIAL, je třeba exportovat své třídy, které mají být zobrazeny klientské aplikace.To je také provádí chůzi CDynLinkLibrary seznam.

V případě pokročilé koncepty MFC ukázkové DLLHUSK, vypadá seznam podobně jako:

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

Knihovna MFCxx.DLL je obvykle poslední v seznamu zdrojů a třídy.Knihovna MFCxx.DLL zahrnuje všechny standardní prostředky knihovny MFC, včetně řetězců pro standardní příkaz identifikátorů.Jeho umístěním na konci seznamu umožňuje DLL knihovny a aplikace klient k dispozici své vlastní kopii standardní prostředky knihovny MFC, ale se spoléhají na sdílené prostředky v MFCxx.DLL místo.

Sloučení zdrojů a názvů tříd všech knihoven DLL do oboru názvů klienta aplikace má nevýhodu, kterou je třeba být opatrní co ID nebo názvy, které vyberete.Můžete samozřejmě zakázat tuto funkci zadních buď zdroje nebo CDynLinkLibrary objekt do klientské aplikace.Ukázka DLLHUSK spravuje jmenný prostor sdílených prostředků použitím více hlavičkových souborů.Viz Technická poznámka: 35 další tipy pro používání souborů sdílených prostředků.

Inicializace knihovny DLL

Jak bylo uvedeno výše, obvykle můžete vytvořit CDynLinkLibrary objekt Export prostředků a tříd do klientské aplikace.Je třeba poskytnout vyvážené vstupní bod knihovny DLL inicializace.Minimálně to je void rutina, která nepřijímá žádné argumenty a vrátí nothing, ale může být jakkoliv chcete.

Každé klientské aplikace, která chce používat knihovny DLL, musí volat tuto inicializační rutina Pokud použijete tento přístup.Také to může přidělit CDynLinkLibrary objektu ve vaší DllMain pouze po volání AfxInitExtensionModule.

Musíte vytvořit inicializační rutina CDynLinkLibrary objektu v aktuální aplikaci haldy, zapojený do vaší rozšiřující DLL informace.To lze provést pomocí následujících kroků:

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

Rutinní název InitXxxDLL v tomto příkladu může být cokoliv chcete.Nemusí být extern "C", ale tím to umožňuje snazší správa seznamu exportu.

[!POZNÁMKA]

Používáte-li vaše rozšiřující knihovny DLL z obvyklé knihovny DLL, je nutné exportovat tento inicializační funkce.Tato funkce musí být volána z běžné knihovny DLL před použitím libovolné třídy rozšíření knihovny DLL nebo zdroje.

Export položek

Jednoduchý způsob exportu vašich tříd je použití __declspec(dllimport) a __declspec(dllexport) v každé třídě a globální funkce, které chcete exportovat.Je mnohem snazší, ale je méně efektivní než pojmenování každé vstupní bod (viz dále), protože máte menší kontrolu nad jaké funkce jsou exportovány a nelze exportovat funkce podle řadu.TESTDLL1 a TESTDLL2 tímto způsobem můžete exportovat své položky.

Efektivnější způsob (a způsob, jímž Knihovna MFCxx.DLL) je ručně exportovat každou položku podle názvů jednotlivých položek v.DEF souboru.Vzhledem k tomu, že jsme exportovat výběrové vývozy z naší knihovny DLL (to znamená, že ne všechno), rozhodneme musí konkrétní rozhraní, která vám přejí vyvážet.To je obtížné, protože k pozměnění názvů do propojovacího programu je třeba zadat ve formuláři položky v.DEF souboru.Exportovat všechny třídy jazyka C++, pokud opravdu potřebujete mít symbolický odkaz.

Pokud jste vyzkoušeli export C++ třídy s.DEF souborů dříve, možná budete chtít vytvořit nástroj, který umožňuje automaticky generovat tento seznam.To lze provést pomocí propojení dvoustupňový proces.Propojit Knihovnu jednou s žádné vývozy a umožnit propojovací program pro generování.Soubor MAPY.Na.Soubor MAPY lze generovat seznam funkcí, které mají být exportovány, takže se některé nové uspořádání lze použít ke generování položky EXPORTU aplikace.DEF souboru.Exportovat seznam MFCxx.DLL a OLE DLL rozšíření databáze, několik tisíc v poli číslo vygenerované takového procesu (i když není zcela automatické a vyžaduje některé ruční ladění vždy jednou za chvíli).

CWinApp vs. CDynLinkLibrary

Rozšiřující knihovna DLL MFC nemá CWinApp-odvozený objekt své vlastní; Místo toho musí pracovat s CWinApp-odvozený objekt klientské aplikace.To znamená, že klientská aplikace vlastní hlavní pumpu zpráv, nečinnou smyčku a podobně.

Pokud potřebuje vaše rozšiřující knihovna DLL MFC spravovat navíc data pro každou aplikaci, můžete odvodit novou třídu z CDynLinkLibrary a vytvořte jej v InitXxxDLL rutiny jsou popsány výše.Je-li spuštěna, může knihovna DLL zkontrolovat seznam aktuální aplikace objektu CDynLinkLibrary k nalezení jedné konkrétní rozšiřující DLL knihovny.

Použití prostředků ve vaší implementaci knihovny DLL

Jak bylo uvedeno výše, provede zatížení prostředků výchozí seznam CDynLinkLibrary objekty, které hledají první EXE nebo DLL, která obsahuje požadovaný prostředek.Všechna rozhraní API knihovny MFC jakož i všechny interní kód používá AfxFindResourceHandle k procházení seznamu zdrojů, chcete-li najít všechny zdroje bez ohledu na to, kde mohou být umístěny.

Pokud chcete načíst prostředky pouze z určitého místa, pomocí rozhraní API AfxGetResourceHandle a AfxSetResourceHandle starý popisovač uložit a nastavit nový úchyt.Nezapomeňte obnovit starý popisovač prostředku před jeho vrácením do klientské aplikace.TESTDLL2 příklad používá tento přístup pro explicitní načítání nabídky.

Procházení seznamem má nevýhody v tom, že je to poněkud pomalejší a vyžaduje to správu rozsahů ID prostředků.Má to výhodu v tom, že klientská aplikace, která je propojena s několika rozšiřujícími DLL knihovnami, může použít jakýkoliv prostředek, poskytnutý DLL knihovnou, aniž by bylo nutné určit popisovač instance knihovny DLL.AfxFindResourceHandle je rozhraní API, použité pro procházení seznamu prostředků pro nalezení odpovídající shody.Přebírá název a typ prostředku a vrací popisovač prostředku, který byl nalezen první (nebo hodnotu NULL).

Vytváření aplikace, která používá knihovnu DLL verze

Požadavky na aplikace

Aplikace, která používá sdílenou verzi knihovny MFC musí následovat několik jednoduchých pravidel:

  • Musí mít CWinApp objekt a postupujte podle standardních pravidel pro zprávy odeslané.

  • Musí být kompilována s sadu příznaků požadované kompilátoru (viz níže).

  • Je nutné propojit s importy knihoven MFCxx.Pomocí nastavení kompilátoru povinné příznaky, určení hlaviček knihovny MFC v době spojení knihovny, které aplikace by měla propojit s.

  • Chcete-li spustit spustitelný soubor, musí být MFCxx.DLL na cestě nebo v kořenovém adresáři systému Windows.

Stavební vývojové prostředí

Pokud používáte soubor vnitřních pravidel s většinou standardních výchozích hodnot, můžete snadno změnit projekt vytvoření verze knihovny DLL.

Následující krok předpokládá, že máte správné funkce aplikace knihovny MFC, spojený s NAFXCWD.LIB (pro ladění) a NAFXCW.LIB (pro maloobchod) a chcete jej převést na používají sdílenou verzi knihovny MFC.Používáte-li prostředí Visual C++ a interní projekt soubor.

  1. Na projekty nabídky, klepněte na tlačítko Vlastnosti.V Obecné stránky v Výchozí projekt, nastavte Microsoft Foundation Classes Použít knihovnu MFC ve sdílené knihovně DLL (MFCxx(d).dll).

Budovy s NMAKE

Pokud používáte externí makefile funkce aplikace Visual C++, nebo přímo pomocí NMAKE, budete muset upravit váš soubor pravidel pro podporu kompilátoru a možnosti propojovacího programu

Povinné příznaky kompilátoru:

  • / D_AFXDLL /MD
    / D_AFXDLL

Standardní knihovna MFC záhlaví třeba tento symbol definovat:

  • /MD
    Aplikace musí používat knihovnu DLL verze knihovny běhu jazyka C

Všechny ostatní příznaky kompilátoru pomocí výchozí knihovny MFC (například _DEBUG pro ladění).

Upravte seznam linker knihoven.Změna NAFXCWD.LIB na MFCxxD.LIB a změnit NAFXCW.LIB pro MFCxx.LIB.Nahraďte LIBC.LIB s MSVCRT.LIB.Stejně jako u jiných knihovny MFC je důležité, že je umístěn MFCxxD.LIB před žádné knihovny modul C runtime.

Volitelně přidat /D_AFXDLL na prodejní a ladicí možnosti kompilátoru zdrojů (ten, který skutečně zkompiluje zdroje s /r).Díky své konečné spustitelný soubor menší sdílením zdrojů, které jsou k dispozici v knihovně MFC DLL.

Úplné sestavení je nutné po provedení těchto změn.

Vytváření vzorků

Většina z ukázkové aplikace knihovny MFC je možné sestavit z Visual C++ nebo sdílený soubor pravidel kompatibilní NMAKE z příkazového řádku.

Převést tyto ukázky použití MFCxx.DLL, můžete načíst.MAK souboru v aplikaci Visual C++ a nastavit možnosti projektu, jak je popsáno výše.Pokud používáte NMAKE sestavení, můžete určit "AFXDLL = 1 v NMAKE příkazového řádku a který bude stavět vzorku pomocí sdílené knihovny MFC.

Vzorek knihovny MFC Upřesnit pojmy DLLHUSK je sestavena s DLL verze knihovny MFC.Tato ukázka nejen ukazuje, jak vytvořit aplikaci, která je spojena s MFCxx.DLL, ale také ilustruje další funkce možnost balení MFC DLL jako DLL rozšíření standardu MFC popsané dále v této technické poznámky.

Poznámky k balení

Maloobchodní verze knihoven DLL (MFCxx [U].(DLL) jsou volně šiřitelné.Ladicí verze knihoven DLL nejsou volně redistribuovatelný a by měl být použit pouze během vývoje aplikace.

Ladění knihoven DLL jsou k dispozici s ladícími informacemi.Spuštění aplikace, stejně jako knihovna DLL můžete sledovat pomocí ladicího programu jazyka Visual C++.Verze knihovny DLL (MFCxx [U].(DLL) neobsahují informace o ladění.

Pokud upravit nebo znovu sestavit DLL knihovny, pak byste měli zavolat jim něco než soubor "MFCxx" The MFC SRC MFCDLL.MAK popisuje možnosti sestavení a obsahuje logiku pro přejmenování knihovny DLL.Přejmenování souborů je nutné, protože tyto DLL knihovny jsou potenciálně sdílena mnoha aplikacemi MFC.S vlastní verze knihoven MFC DLL nahrazení nainstalovaná v systému může dojít k přerušení jiné aplikace knihovny MFC pomocí sdílené knihovny MFC DLL.

Opětovné sestavení knihovny DLL MFC se nedoporučuje.

Způsob implementace MFCxx.DLL

Následující část popisuje způsob implementace MFC DLL (Knihovna MFCxx.DLL a MFCxxD.DLL).Pochopení, že zde nejsou podrobnosti také důležité všechny Chcete-li je použít MFC DLL s aplikací.Podrobnosti zde nejsou podstatné pro porozumění, jak psát rozšiřující DLL knihovna typu MFC, ale Princip této implementace můžete napsat vlastní knihovny DLL.

Přehled provádění

Knihovna MFC DLL je ve skutečnosti zvláštní případ MFC příponu DLL výše popsaným způsobem.Má velmi velký počet vývozů pro velký počet tříd.Existuje několik dalších věcí děláme v knihovně MFC DLL vytvořit ještě více zvláštní než běžné knihovny DLL rozšíření.

Win32 provede většinu práce

16bitové verze knihovny MFC potřebný počet speciální techniky včetně údajů za app v segmentu zásobníku, speciální segmenty vytvořeny některé kód sestavení 80 x 86, kontexty za zpracování výjimek a jiné techniky.Win32 přímo podporuje za zpracování dat v knihovně DLL, která je, co má ve většině případů.Knihovna MFCxx.DLL je z velké části právě NAFXCW.LIB zabalen v knihovně DLL.Pokud se podíváte na zdrojový kód knihovny MFC, zjistíte velmi málo #ifdef _AFXDLL, jelikož se jedná o velmi málo zvláštních případů, které je třeba provést.Zvláštní případy, které jsou konkrétně řešit Win32 v systému Windows 3.1 (označováno také jako Win32s).Win32s neobsahuje podpora dat knihovny DLL na proces přímo tak MFC DLL, musíte použít místní úložiště (TLS) rozhraní Win32 API získat místní data procesu.

Dopad na knihovnu zdrojů, další soubory

Dopad _AFXDLL verze na normální zdroje knihovny MFC třídy a záhlaví je relativně malé.Je speciální verze souboru (AFXV_DLL.H) stejně jako další hlavičky souboru (AFXDLL_.H) zahrnuty v hlavním AFXWIN.H záhlaví.AFXDLL_.H záhlaví obsahuje CDynLinkLibrary třídy a další podrobnosti o implementaci obou _AFXDLL aplikací a DLL rozšíření standardu MFC.AFXDLLX.H záhlaví je k dispozici pro vytváření DLL rozšíření standardu MFC (podrobnosti naleznete v části výše).

Běžné zdroje knihovny MFC MFC SRC mají některé další Podmíněné kódy pod _AFXDLL #ifdef.Na další zdrojový soubor (DLLINIT.CPP) obsahuje navíc knihovna DLL inicializuje kódem a jiné lepidlo pro sdílenou verzi knihovny MFC.

S cílem vytvořit sdílenou verzi knihovny MFC, jsou k dispozici další soubory. (Viz níže Další informace o vytvoření knihovny DLL.)

  • Dva.DEF souborů slouží k exportu knihovny DLL MFC vstupní body pro ladění (MFCxxD.DEF) a (MFCxx.DEF) verzi knihovny DLL.

  • An.RC souboru (MFCDLL.RC) obsahuje všechny standardní prostředky MFC a VERSIONINFO prostředků pro knihovny DLL.

  • A.CLW soubor (MFCDLL.CLW) je k dispozici při procházení knihovny MFC třídy pomocí ClassWizard.Poznámka: Tato funkce není specifický pro knihovnu DLL verze knihovny MFC.

Správa paměti

Knihovna MFCxx.DLL pomocí aplikace používá běžné přidělování paměti MSVCRTxx.DLL, sdílené knihovny DLL C runtime poskytované.A také samotnými knihovnami MFC DLL, aplikace a všechny rozšiřující DLL knihovny, použijte toto přidělování sdílené paměti.Pomocí sdílené knihovny DLL pro přidělení paměti MFC Knihovny DLL můžete přidělit paměť, která je uvolněna později aplikací nebo naopak.Vzhledem k tomu, že aplikace a knihovny DLL, musíte použít stejné přidělování, neměli přepsat globální C++ operator new nebo operator delete.Stejná pravidla se vztahují na zbytku rutiny C Runtime paměti přidělení (například malloc, realloc, zdarmaa další).

Řadové číslovky a __declspec(dllexport) třídy a názvu knihovny DLL

Doporučujeme nepoužívat class**__declspec(dllexport)** funkce kompilátoru jazyka C++. Místo toho seznam vývoz je součástí zdroje knihovny tříd (MFCxx.DEF a MFCxxD.DEF).Jsou exportovány pouze tyto vyberte sadu vstupních bodů (funkce a data).Další symboly, jako soukromý implementační funkce knihovny MFC nebo třídy, nejsou exportovány všechny vývozy jsou prováděny podle pořadí bez řetězec název v tabulce Název rezidentské a nerezidentské.

Pomocí class**__declspec(dllexport)** může být přijatelnou alternativu pro vytváření DLL knihovnen menší, ale v případě velké knihovny DLL jako MFC výchozí export mechanismus má účinnosti a kapacity omezení. 

Co to znamená pro všechny je, že jsme balíček velké množství funkcí v MFCxx.DLL, která je pouze cca 800 KB bez ohrožení mnohem spuštění nebo načtení rychlost uvolňování.Knihovna MFCxx.DLL by byla 100 kB větší by nebyl tento postup použít.To také umožňuje přidat další vstupní body na konci.DEF souboru umožňuje jednoduchou správu verzí bez ohrožení účinnosti rychlost a velikost exportu podle pořadí.Hlavní verze revize v knihovně tříd knihovny MFC se změní název knihovny.To znamená MFC30.DLL je redistributable DLL obsahující třídu knihovny MFC verze 3.0.Upgrade této knihovny DLL, Řekněme v hypotetické 3.1 knihovny MFC, knihovny DLL by se jmenovala MFC31.Knihovna DLL místo.Znovu Pokud upravíte zdrojový kód knihovny MFC k vytvoření vlastní verzi knihovny MFC DLL, použijte jiný název (a pokud možno bez "MFC" v názvu).

Viz také

Další zdroje

Technické poznámky podle čísel

Technické poznámky podle kategorií