Sdílet prostřednictvím


Vzájemné importy

Export nebo import do jiného spustitelného souboru představuje komplikace, když jsou importy vzájemné (nebo cyklické). Například dvě knihovny DLL importují symboly z sebe navzájem, podobně jako vzájemně rekurzivní funkce.

Problém s vzájemně importujícími spustitelnými soubory (obvykle dll) spočívá v tom, že ani jeden z nich nelze sestavit bez sestavení druhého souboru. Každý proces sestavení vyžaduje jako vstup knihovnu importu vytvořenou jiným procesem sestavení.

Řešením je použít nástroj LIB s možností /DEF, která vytváří knihovnu importu bez sestavení spustitelného souboru. Pomocí tohoto nástroje můžete sestavit všechny knihovny importu, které potřebujete, bez ohledu na to, kolik knihoven DLL se týká nebo jak složité jsou závislosti.

Obecným řešením pro zpracování vzájemných importů je:

  1. Vezměte každou knihovnu DLL zase. (Jakákoli objednávka je proveditelná, i když některé objednávky jsou optimální.) Pokud všechny potřebné knihovny importu existují a jsou aktuální, spusťte LINK a sestavte spustitelný soubor (DLL). Tím se vytvoří knihovna importu. V opačném případě spusťte knihovnu LIB a vytvořte knihovnu importu.

    Spuštění knihovny LIB s parametrem /DEF vytvoří další soubor s příponou . Rozšíření EXP. Tá. Soubor EXP se musí použít později k sestavení spustitelného souboru.

  2. Po použití linku nebo knihovny LIB k sestavení všech knihoven importu se vraťte a spusťte LINK a sestavte všechny spustitelné soubory, které nebyly sestaveny v předchozím kroku. Všimněte si, že odpovídající soubor .exp musí být zadán na řádku LINK.

    Pokud byste dříve spustili nástroj LIB pro vytvoření knihovny pro import knihovny DLL1, knihovna LIB by vytvořila také soubor DLL1.exp. Při sestavování knihovny DLL1.dlll je nutné použít knihovnu DLL1.exp jako vstup pro propojení.

Následující obrázek znázorňuje řešení pro dva vzájemně importující knihovny DLL, DLL1 a DLL2. Krok 1 je spuštění knihovny LIB se sadou možností /DEF v knihovně DLL1. Krok 1 vytvoří knihovnu DLL1.lib, knihovnu importu a knihovnu DLL1.exp. V kroku 2 se knihovna importu používá k sestavení knihovny DLL2, která pak vytvoří knihovnu importu pro symboly knihovny DLL2. Krok 3 sestaví knihovnu DLL1 pomocí knihovny DLL1.exp a DLL2.lib jako vstup. Všimněte si, že soubor .exp pro knihovnu DLL2 není nutný, protože knihovna LIB nebyla použita k sestavení knihovny DLL2 pro import.

Diagram that shows the inputs and outputs when you use mutual imports to link two DLLs.
Propojení dvou knihoven DLL se vzájemnými importy

Omezení _AFXEXT

Pro knihovny DLL rozšíření MFC můžete použít symbol preprocesoru _AFXEXT , pokud nemáte více vrstev rozšiřujících knihoven DLL mfc. Pokud máte knihovny DLL rozšíření MFC, které volají nebo odvozují z tříd ve vlastních rozšiřujících knihovnách MFC DLL, které pak odvozují z tříd MFC, je nutné použít vlastní symbol preprocesoru, abyste se vyhnuli nejednoznačnosti.

Problém je v tom, že v systému Win32 musíte explicitně deklarovat všechna data, jako __declspec(dllexport) by se exportovala z knihovny DLL, a __declspec(dllimport) pokud se má importovat z knihovny DLL. Při definování _AFXEXTse hlavičky MFC ujistěte, že je správně definován AFX_EXT_CLASS .

Pokud máte více vrstev, jeden symbol, například AFX_EXT_CLASS , nestačí, protože knihovna DLL rozšíření MFC může exportovat nové třídy a importovat další třídy z jiné knihovny DLL rozšíření MFC. Chcete-li tento problém vyřešit, použijte speciální preprocesor symbol, který indikuje, že vytváříte samotnou knihovnu DLL versus použití knihovny DLL. Představte si například dvě rozšiřující knihovny MFC DLL, A.dll a B.dll. Každá z nich exportuje některé třídy v A.h a B.h v uvedeném pořadí. 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 sestavení A.dll, je sestaven s /D A_IMPL a při B.dll je sestaven, je sestaven s /D B_IMPL. Pomocí samostatných symbolů pro každou knihovnu DLL CExampleB je exportován a CExampleA importován při sestavování B.dll. CExampleA je exportován při sestavování knihovny A.dll a importován při použití B.dll (nebo některého jiného klienta).

Tento typ vrstvení nelze provést při použití předdefinovaných symbolů AFX_EXT_CLASS a _AFXEXT preprocesoru. Výše popsaná technika tento problém řeší způsobem, který není rozdíl od samotného mechanismu, který mfc používá při sestavování svých aktivních technologií, databází a rozšiřujících knihoven DLL síťové knihovny MFC.

Neexportování celé třídy

Pokud neexportujete celou třídu, musíte zajistit, aby se správně exportovaly potřebné datové položky vytvořené makry MFC. Můžete to udělat tak, že předefinujte AFX_DATA makro konkrétní třídy. To by se mělo provést pokaždé, 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

Co chcete udělat?

O čem chcete vědět víc?

Viz také

Import a export