Share via


Règles générales et limitations

Section spécifique à Microsoft

  • Si vous déclarez une fonction ou un objet sans l’attribut ou dllexport la dllimport fonction, la fonction ou l’objet n’est pas considéré comme faisant partie de l’interface DLL. Par conséquent, la définition de la fonction ou de l'objet doit être présente dans ce module ou dans un autre module du même programme. Pour faire partie de la fonction ou de l’objet de l’interface DLL, vous devez déclarer la définition de la fonction ou de l’objet dans l’autre module en tant que dllexport. Sinon, une erreur d'éditeur de liens est générée.

    Si vous déclarez une fonction ou un objet avec l’attribut dllexport , sa définition doit apparaître dans un module du même programme. Sinon, une erreur d'éditeur de liens est générée.

  • Si un seul module de votre programme contient à la fois dllimport et dllexport des déclarations pour la même fonction ou le même objet, l’attribut dllexport est prioritaire sur l’attribut dllimport . Toutefois, un avertissement du compilateur est généré. Par exemple :

    __declspec( dllimport ) int i;
    __declspec( dllexport ) int i;   // Warning; inconsistent;
                                     // dllexport takes precedence.
    
  • En C++, vous pouvez initialiser un pointeur de données local global déclaré ou statique ou avec l’adresse d’un objet de données déclaré avec l’attribut dllimport , ce qui génère une erreur en C. En outre, vous pouvez initialiser un pointeur de fonction local statique avec l’adresse d’une fonction déclarée avec l’attribut dllimport . En C, ce type d'assignation définit le pointeur sur l'adresse de la conversion de code d'importation de la DLL (stub de code qui transfère un contrôle à la fonction) plutôt que l'adresse de la fonction. En C++, il définit le pointeur sur l'adresse de la fonction. Par exemple :

    __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++
    }
    

    Toutefois, étant donné qu’un programme qui inclut l’attribut dllexport dans la déclaration d’un objet doit fournir la définition de cet objet quelque part dans le programme, vous pouvez initialiser un pointeur de fonction statique global ou local avec l’adresse d’une dllexport fonction. De même, vous pouvez initialiser un pointeur de données statiques global ou local avec l'adresse d'un objet de données dllexport. Par exemple, le code suivant ne génère pas d'erreur en C ni en 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
    }
    
  • Si vous appliquez dllexport à une classe régulière qui a une classe de base qui n’est pas marquée comme dllexportétant, le compilateur génère C4275.

    Le compilateur génère le même avertissement si la classe de base est une spécialisation d'un modèle de classe. Pour contourner ce problème, marquez la classe de base avec dllexport. Le problème avec une spécialisation d’un modèle de classe est l’emplacement où placer le __declspec(dllexport); vous n’êtes pas autorisé à marquer le modèle de classe. Au lieu de cela, instanciez explicitement le modèle de classe et marquez cette instanciation explicite avec dllexport. Par exemple :

    template class __declspec(dllexport) B<int>;
    class __declspec(dllexport) D : public B<int> {
    // ...
    

    Cette solution de contournement échoue si l’argument template est la classe dérivée. Par exemple :

    class __declspec(dllexport) D : public B<D> {
    // ...
    

    Étant donné qu’il s’agit d’un modèle courant avec des modèles, le compilateur a modifié la sémantique du dllexport moment où il est appliqué à une classe qui a une ou plusieurs classes de base et lorsqu’une ou plusieurs classes de base est une spécialisation d’un modèle de classe. Dans ce cas, le compilateur s’applique dllexport implicitement aux spécialisations des modèles de classe. Vous pouvez effectuer les opérations suivantes et ne pas recevoir d’avertissement :

    class __declspec(dllexport) D : public B<D> {
    // ...
    

FIN de la section spécifique à Microsoft

Voir aussi

dllexport, dllimport