Share via


Allgemeine Regeln und Einschränkungen

Microsoft-spezifisch

  • Wenn Sie eine Funktion oder ein Objekt ohne das dllimport Attribut dllexport deklarieren, wird die Funktion oder das Objekt nicht als Teil der DLL-Schnittstelle betrachtet. Daher muss die Definition der Funktion oder des Objekts in diesem Modul oder in einem anderen Modul desselben Programms vorhanden sein. Um die Funktion oder das Objekt teil der DLL-Schnittstelle zu machen, müssen Sie die Definition der Funktion oder des Objekts im anderen Modul als dllexportdeklarieren. Andernfalls wird ein Linkerfehler generiert.

    Wenn Sie eine Funktion oder ein Objekt mit dem dllexport Attribut deklarieren, muss die Definition in einem Modul desselben Programms angezeigt werden. Andernfalls wird ein Linkerfehler generiert.

  • Wenn ein einzelnes Modul in Ihrem Programm sowohl Deklarationen als auch dllimportdllexport Deklarationen für dieselbe Funktion oder dasselbe Objekt enthält, hat das dllexport Attribut Vorrang vor dem dllimport Attribut. Es wird jedoch eine Compilerwarnung ausgegeben. Beispiel:

    __declspec( dllimport ) int i;
    __declspec( dllexport ) int i;   // Warning; inconsistent;
                                     // dllexport takes precedence.
    
  • In C++ können Sie einen global deklarierten oder statischen lokalen Datenzeiger oder die Adresse eines mit dem dllimport Attribut deklarierten Datenobjekts initialisieren, das einen Fehler in C generiert. Darüber hinaus können Sie einen statischen lokalen Funktionszeiger mit der Adresse einer Funktion initialisieren, die mit dem dllimport Attribut deklariert ist. In C legt eine solche Zuweisung den Zeiger auf die Adresse des DLL-Importthunks (ein Codestub, der die Steuerung an die Funktion übergibt) anstatt auf die Adresse der Funktion fest. In C++ wird der Zeiger auf die Adresse der Funktion festgelegt. Beispiel:

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

    Da jedoch ein Programm, das das dllexport Attribut in die Deklaration eines Objekts einschließt, die Definition für dieses Objekt irgendwo im Programm bereitstellen muss, können Sie einen globalen oder lokalen statischen Funktionszeiger mit der Adresse einer dllexport Funktion initialisieren. Ebenso können Sie einen globalen oder lokalen statischen Datenzeiger mit der Adresse eines dllexport-Datenobjekts initialisieren. Zum Beispiel generiert der folgende Code keine Fehler in C oder 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
    }
    
  • Wenn Sie auf eine normale Klasse anwenden dllexport , die über eine Basisklasse verfügt, die nicht als dllexportgekennzeichnet ist, generiert der Compiler C4275.

    Der Compiler generiert dieselbe Warnung, wenn die Basisklasse eine Spezialisierung einer Klassenvorlage ist. Um dies zu umgehen, markieren Sie die Basisklasse mit dllexport. Das Problem mit einer Spezialisierung einer Klassenvorlage besteht darin, wo die __declspec(dllexport)Klassenvorlage platziert werden soll. Sie dürfen die Klassenvorlage nicht markieren. Instanziieren Sie stattdessen die Klassenvorlage explizit, und markieren Sie diese explizite Instanziierung mit dllexport. Beispiel:

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

    Diese Problemumgehung funktioniert nicht, wenn das Vorlagenargument die ableitende Klasse ist. Beispiel:

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

    Da dies gängige Muster mit Vorlagen ist, hat der Compiler die Semantik dllexport geändert, wenn sie auf eine Klasse angewendet wird, die eine oder mehrere Basisklassen enthält und wenn eine oder mehrere Basisklassen eine Spezialisierung einer Klassenvorlage sind. In diesem Fall gilt der Compiler implizit für dllexport die Spezialisierungen von Klassenvorlagen. Sie können die folgenden Aktionen ausführen und keine Warnung erhalten:

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

Ende Microsoft-spezifisch

Siehe auch

dllexport, dllimport