Reglas generales y Limitaciones
Específicos de Microsoft
Si declara una función o un objeto sin el atributo de dllimport o de dllexport , la función o el objeto no se considera parte de la interfaz DLL.Por consiguiente, la definición de la función o el objeto debe estar presente en ese módulo o en otro módulo del mismo programa.Para crear la parte de la función o el objeto de interfaz DLL, debe declarar la definición de función o de objeto del otro módulo como dllexport.Si no, se genera un error del vinculador.
Si declara una función o un objeto con el atributo de dllexport , su definición debe aparecer en algún de módulo del mismo programa.Si no, se genera un error del vinculador.
Si un módulo único en el programa contiene dllimport y las declaraciones de dllexport para la misma función u objeto, el atributo de dllexport tiene prioridad sobre el atributo de dllimport .Sin embargo, se genera una advertencia del compilador.Por ejemplo:
__declspec( dllimport ) int i; __declspec( dllexport ) int i; // Warning; inconsistent; // dllexport takes precedence.
En C++, puede inicializar un puntero de datos local global declarado o estático o con la dirección de un objeto de datos declarado con el atributo de dllimport , que genera un error en C.Además, puede inicializar un puntero a función local estático con la dirección de una función declarada con el atributo de dllimport .En C, por asignación establece el puntero a la dirección del procesador de importación del archivo DLL (un código auxiliar de código que transfiere el control a la función) en lugar de la dirección de la función.en C++, establece el puntero a la dirección de la función.Por ejemplo:
__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++ }
Sin embargo, dado que un programa que incluye el atributo de dllexport en la declaración de un objeto debe proporcionar la definición de ese objeto en alguna parte del programa, puede inicializar un puntero a función estática global o local con la dirección de una función de dllexport .De igual forma, puede inicializar un puntero de datos estáticos global o local con la dirección de un objeto de datos de dllexport .Por ejemplo, el siguiente código no genera errores en C o 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 }
Debido a un cambio de comportamiento escriba en Visual C++ .NET para crear la aplicación de dllexport más coherente entre las clases normales y las especializaciones de las plantillas de clase, si aplica dllexport a una clase normal que tiene una clase base que no está marcado como dllexport, el compilador generará C4275.
El compilador genera la misma advertencia si la clase base es una especialización de una plantilla de clase.Para evitar esto, marque la clase base con dllexport.El problema de una especialización de una plantilla de clase es donde colocar __declspec (dllexport); a no se permite marcar la plantilla de clase.En su lugar, explícitamente cree instancias de la plantilla de clase y marque esta instancia explícita con dllexport.Por ejemplo:
template class __declspec(dllexport) B<int>; class __declspec(dllexport) D : public B<int> { // ...
Esta solución alternativa no se supera si el argumento de plantilla es la clase derivada.Por ejemplo:
class __declspec(dllexport) D : public B<D> { // ...
Dado que éste es modelo común con plantillas, el compilador realiza la semántica de dllexport cuando se aplica a una clase que tiene una o más clases base y cuando uno o más de las clases base son una especialización de una plantilla de clase.En este caso, el compilador aplica implícitamente dllexport a las especializaciones de las plantillas de clase.En Visual C++ .NET, un usuario puede hacer lo siguiente y no recibir una advertencia:
class __declspec(dllexport) D : public B<D> { // ...