Obecná pravidla a omezení
Specifické pro produkty společnosti Microsoft
Pokud deklarujete funkci nebo objekt bez atributu dllimport nebo dllexport, funkce nebo objekt není považován za součást rozhraní knihovny DLL.Proto musí být definice funkce nebo objektu přítomna v tomto modulu nebo v jiném modulu téhož programu.Chcete-li, aby funkce nebo objekt byl součástí rozhraní knihovny DLL, je nutné deklarovat definici funkce nebo objektu v jiném modulu označeném atributem dllexport.Jinak dojde k chybě propojovacího programu.
Pokud deklarujete funkci nebo objekt s atributem dllexport, jeho definice musí být uvedena v některém modulu téhož programu.Jinak dojde k chybě propojovacího programu.
Pokud jeden modul v aplikaci obsahuje deklarace obou atributů dllimport a dllexport pro stejnou funkci nebo objekt, má atribut dllexport přednost před atributem dllimport.Ačkoli bude vygenerováno upozornění kompilátoru.Příklad:
__declspec( dllimport ) int i; __declspec( dllexport ) int i; // Warning; inconsistent; // dllexport takes precedence.
V jazyce C++ lze inicializovat globálně deklarovaný nebo statický místní ukazatel na data nebo s adresou datového objektu deklarovaného s atributem dllimport, který v jazyce C vygeneruje chybu.Kromě toho lze inicializovat ukazatel na statickou místní funkci s adresou funkce deklarované s atributem dllimport.V jazyce C toto přiřazení nastaví ukazatele na adresu převodu importu knihovny DLL (zástupný kód, který předává řízení funkci) namísto adresy funkce.V jazyce C++ nastaví ukazatele na adresu funkce.Příklad:
__declspec( dllimport ) void func1( void ); __declspec( dllimport ) int i; int *pi = &i; // Error in C static void ( *pf )( void ) = &func1; // Address of thunk in C, // function in C++ void func2() { static int *pi = &i; // Error in C static void ( *pf )( void ) = &func1; // Address of thunk in C, // function in C++ }
Nicméně, protože program, který obsahuje atribut dllexport v deklaraci objektu musí poskytnout definici tohoto objektu jinde v programu, lze inicializovat globální nebo místní ukazatel na statickou funkci adresou funkce s atributem dllexport.Podobně lze inicializovat globální nebo místní ukazatel na statická data adresou datového objektu s atributem dllexport.Následující kód například nevygeneruje v jazyce C nebo C++ chyby:
__declspec( dllexport ) void func1( void ); __declspec( dllexport ) int i; int *pi = &i; // Okay static void ( *pf )( void ) = &func1; // Okay void func2() { static int *pi = &i; // Okay static void ( *pf )( void ) = &func1; // Okay }
Z důvodu změny v chování zavedené v jazyce Visual C++ .NET, aby bylo uplatňování atributu dllexport více konzistentní mezi běžnými třídami a specializacemi šablon tříd, použijete-li atribut dllexport na běžnou třídu, která má základní třídu neoznačenou atributem dllexport, kompilátor vygeneruje upozornění C4275.
Kompilátor vygeneruje stejné upozornění, pokud je základní třída specializací šablony třídy.Chcete-li tento problém obejít, označte základní třídu atributem dllexport.Problém se specializací šablony třídy je umístění __declspec(dllexport). Nelze označit tuto šablonu třídy.Namísto toho explicitně vytvořte instanci šablony třídy a označte tuto explicitní instanci atributem dllexport.Příklad:
template class __declspec(dllexport) B<int>; class __declspec(dllexport) D : public B<int> { // ...
Toto řešení selže, pokud je argument šablony odvozená třída.Příklad:
class __declspec(dllexport) D : public B<D> { // ...
Vzhledem k tomu, že je to společný vzor šablon, kompilátor změní sémantiku atributu dllexport, když je použit na třídu, která má jednu nebo více základních tříd a když je jedna nebo více základních tříd specializací šablony třídy.V tomto případě kompilátor implicitně použije atribut dllexport na specializace šablony třídy.V jazyce Visual C++ .NET může uživatel provést následující kroky a tak potlačit varování:
class __declspec(dllexport) D : public B<D> { // ...