一般的な規則と制限
Microsoft 固有の仕様 →
関数を宣言または dllimport または dllexport の属性なしオブジェクトにすると関数またはオブジェクトの DLL インターフェイスの一部とは見なされません。したがって関数またはオブジェクトの定義はそのモジュールまたは同じプログラムの別のモジュールになります。関数を行うかまたは DLL インターフェイスの部分にオブジェクト関数のシグネチャを宣言したり他のモジュールで dllexport と異なるする必要があります。それ以外の場合リンカー エラーが生成されます。
関数を宣言または dllexport の属性とするとオブジェクト定義は同じプログラムのモジュールで使用する必要があります。それ以外の場合リンカー エラーが生成されます。
プログラムの一つのモジュールが dllimport が含まれ同じ dllexport の宣言が機能するためにはオブジェクトとdllexport の属性は dllimport の属性よりも優先されます。ただしコンパイラの警告が生成されます。次に例を示します。
__declspec( dllimport ) int i; __declspec( dllexport ) int i; // Warning; inconsistent; // dllexport takes precedence.
C++ ではC エラーが発生する dllimport の属性で宣言されたデータ オブジェクトのアドレスを使用してグローバルに宣言または静的なローカル データ ポインターまたはを初期化できます。またdllimport の属性で宣言された関数のアドレスを持つ静的なローカル関数ポインターを初期化できます。C ではこのような型で DLL インポートのサンク (コード スタブ関数へのアクセス制御) アドレスに関数のアドレスではなくポインターを設定します。C++ では関数のアドレスへのポインターを設定します。次に例を示します。
__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++ }
ただしオブジェクトの宣言に dllexport の属性を含むプログラムをプログラムでそのオブジェクト定義をどこかに指定する必要があるためdllexport 関数のアドレスを持つグローバル リソース ファイルまたはローカルの静的関数ポインターを初期化できます。同様にdllexport のデータ オブジェクトのアドレスを持つグローバル リソース ファイルまたはローカルの静的データ ポインターを初期化できます。たとえば次のコードではC または 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 }
dllexport としてマークされていない基本クラスを持つ通常のクラスに dllexport を適用する動作を変更するために dllexport アプリケーションを行うにはVisual C++ .NET で通常のクラス間で一貫性ように導入するクラス テンプレートの特殊化はC4275コンパイラが生成されます。
コンパイラは基本クラスがクラス テンプレートの特殊化で同じ警告が生成されます。このエラーを解決するにはdllexport の基本クラスを指定します。クラス テンプレートの特殊化の問題は __declspec (dllexport) を配置する場所を示します ; クラス テンプレートを指定できません。代わりに明示的にクラス テンプレートをインスタンス化しdllexport を明示的にインスタンス化を設定します。次に例を示します。
template class __declspec(dllexport) B<int>; class __declspec(dllexport) D : public B<int> { // ...
この問題を回避するにはテンプレート引数から派生したクラスである場合に失敗します。次に例を示します。
class __declspec(dllexport) D : public B<D> { // ...
これはテンプレートを使用して一般的なパターンであるためコンパイラは一つ以上の基本クラスがある場合基本クラスの一つ以上がクラス テンプレートの特化型を持つクラスに適用される dllexport のセマンティクスは変更されています。この場合コンパイラはクラス テンプレートの特化型に暗黙的に dllexport を適用します。Visual C++ .NET ではユーザーは次のようにし警告を取得できます :
class __declspec(dllexport) D : public B<D> { // ...