Limitações e regras gerais
Específicos do Microsoft
Se você declarar uma função ou um objeto sem a dllimport ou dllexport atributo, a função ou o objeto não é considerado parte da interface do DLL.Portanto, a definição da função ou objeto deve estar presente neste módulo, ou em outro módulo do mesmo programa.Para tornar a parte da função ou objeto da interface da DLL, você deve declarar a definição da função ou objeto no módulo como dllexport.Caso contrário, será gerado um erro de vinculador.
Se você declarar uma função ou objeto com o dllexport de atributo, sua definição deve aparecer em algum módulo do mesmo programa.Caso contrário, será gerado um erro de vinculador.
Se um único módulo no seu programa contém ambos dllimport e dllexport declarações para a mesma função ou objeto, o dllexport atributo tem precedência sobre o dllimport atributo.No entanto, um aviso do compilador é gerado.Por exemplo:
__declspec( dllimport ) int i; __declspec( dllexport ) int i; // Warning; inconsistent; // dllexport takes precedence.
No C++, você pode inicializar um ponteiro de dados local estático ou declarados globalmente ou com o endereço de um objeto de dados declarado com o dllimport atributo, o que gera um erro em c.Além disso, você pode inicializar um ponteiro de função estática de local com o endereço de uma função declarada com o dllimport atributo.Em C, como uma atribuição define o ponteiro para o endereço da conversão de importação de DLL (um stub de código que transfere o controle para a função) em vez do endereço da função.No C++, ele define o ponteiro para o endereço da função.Por exemplo:
__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++ }
No entanto, como um programa que inclui o dllexport atributo na declaração de um objeto deve fornecer a definição desse objeto em algum lugar no programa, você pode inicializar um ponteiro de função estática global ou local com o endereço de um dllexport função.Da mesma forma, você pode inicializar um ponteiro de dados estáticos global ou local com o endereço de um dllexport o objeto de dados.Por exemplo, o código a seguir não gera erros em c ou C++:
__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 }
Devido a uma alteração no comportamento de apresentar no Visual C++.NET para tornar o aplicativo de dllexport mais consistente entre classes normais e especializações dos modelos de classe, se você aplicar dllexport a uma classe regular que tem uma classe base que não está marcada como dllexport, o compilador irá gerar C4275.
O compilador gera o mesmo aviso se a classe base é uma especialização de um modelo de classe.Para contornar isso, marcar a classe base com dllexport.O problema com uma especialização de um modelo de classe é onde colocar a __declspec(dllexport); Você não tem permissão para marcar o modelo de classe.Em vez disso, explicitamente instanciar o modelo de classe e marcar esta instanciação explícita com dllexport.Por exemplo:
template class __declspec(dllexport) B<int>; class __declspec(dllexport) D : public B<int> { // ...
Essa solução alternativa falhará se o argumento de modelo é a classe derivada.Por exemplo:
class __declspec(dllexport) D : public B<D> { // ...
Como esse é um padrão comum com modelos, o compilador alterado a semântica do dllexport quando ele é aplicado a uma classe que tenha uma ou mais classes de base e quando uma ou mais das classes base são uma especialização de um modelo de classe.Nesse caso, o compilador aplica implicitamente dllexport para as especializações de modelos de classe.No Visual C++.NET, um usuário pode fazer o seguinte e não receber um aviso:
class __declspec(dllexport) D : public B<D> { // ...