1. ホーム
  2. c++

__declspec(dllexport) と __declspec(dllimport)

2022-03-02 22:52:30

相違点

       どちらもDLL内のキーワード、つまりexportとimportです。これらは、DLL内部からクラスや関数、データをエクスポート、インポートする際に使用されます。

      dllexportは、これらのクラス、関数、およびデータがアサートされるときに使用されます。つまり、(dllexport) は DLL 内の関連するコード (クラス、関数、データ) を他のアプリケーションで使用できるように公開していることを示すために使用されます。(dllexport) キーワードの使用は、(dllexport) キーワードの直後にある関連コンテンツが他のアプリケーションで使用可能であることを宣言しているのと同じです。

      dllimportは、外部プログラムがDLL内の関連コンテンツを使用する必要がある場合に使用されるキーワードです。外部プログラムが DLL の内部コード (クラス、関数、グローバル変数) を使用したい場合、(dllimport) キーワードを使用してプログラム内で使用するコードを宣言するだけでよく、つまり (dllimport) キーワードは、外部プログラムが DLL の内部コンテンツを使用する必要がある場合にのみ使用されるキーワードです。(dllimport)機能は、DLLからアプリケーションに関連するコードを挿入することです。

      declspec(dllexport) と _declspec(dllimport) は互いに呼応しており、dllexport で DLL 内部の宣言を行って初めて、dllimport で外部関数内の関連コードをインポートすることができます。

一般的な使用方法

    使い勝手をよくするために、エクスポートする必要のあるクラスや関数の前に使うマクロ DLL_EXPORT をコード内に定義することがありますが、このマクロを次のように定義します。

#ifdef DLL_EXPORTS
 
      #define SIMPLE_CLASS_EXPORT __declspec(dllexport)
 
#else
 
       #define SIMPLE_CLASS_EXPORT __declspec(dllimport)
 
#endif


ダイナミック・ライブラリとして、エクスポートする必要があるクラスや関数は、エクスポートする前にキーワード __declspec(dllexport) で宣言する必要があるので、ダイナミック・ライブラリではマクロ DLL_EXPORTS を定義する必要があります(このマクロは Vistualstudio を使用してダイナミック・ライブラリ・プロジェクトを構築したときに既に定義されています)。

    アプリケーションはキーワード __declspec(dllimport) を使用する必要があるため、マクロ DLL_EXPORTS を定義することができません。

dllimportは省略可能ですか?

       しかし、__declspec(dllimport)のMSDNのドキュメントがちょっとおかしいので、MSDNに書いてあることを見てみましょう。

          コードは __declspec(dllimport) なしでも正しくコンパイルされますが、 __declspec(dllimport) を使用すると、コンパイラーはより良いコードを生成できるようになります。コンパイラーは、関数が DLL に存在するかどうかを判断できるため、DLL 境界をまたぐ関数呼び出しに通常存在する間接アドレス レベルをスキップしたコードを生成できるようになり、より優れたコードを生成できるようになりました。ただし、DLL で使用される変数をインポートするには、__declspec(dllimport) を使用する必要があります。

      __declspec(dllimport) を使うとより良いコードが生成されるのは理解できるが、DLL で使用する変数をエクスポートするために使用しなければならない、本当にそうだろうか?では、テストしてみましょう。

      SimpleClass.hとSimpleClass.cppからなるダイナミックライブラリを作成します。SimpleClass.hのコード実装は以下の通りです。

//file SimpleClass.h
#ifndef _SIMPLE_CLASS_H_
#define _SIMPLE_CLASS_H_
 
#ifdef DLL_EXPORTS
    #define SIMPLE_CLASS_EXPORT__declspec(dllexport)
#else
    #define SIMPLE_CLASS_EXPORT
#endif
 
extern int SIMPLE_CLASS_EXPORT g_Vaule; //global variable
 
class SIMPLE_CLASS_EXPORT CSimpleClass
{
public:
    CSimpleClass(void);
    ~CSimpleClass(void);
     int GetVale(void)const;
};
#endif


SimpleClass.cppのコードでは、以下のように実装されています。

//SimpleClass.cpp
 
#include "SimpleClass.h"
 
int g_Vaule = 100;
 
CSimpleClass::CSimpleClass(void)
    :m_iValue(100)
{}
CSimpleClass::~CSimpleClass(void)
{}
int CSimpleClass::GetVale(void)const
{
    return g_Vaule;
}


アプリケーションがg_Vauleを直接使用しない場合、コンパイルは正常に行われ、GetValeの呼び出しは正しく100を返します。

    しかし、アプリケーションで直接g_Vauleを使用した場合、以下のようにコンパイルエラーになります。

1>main.obj : error LNK2001: unresolvedexternal symbol "int g_Vaule" (?g_Vaule@@3HA)

    SimpleClass.hのマクロ定義を以下の値に変更すると、正常にコンパイルされます。

#ifdef DLL_EXPORTS
      #define SIMPLE_CLASS_EXPORT __declspec(dllexport)
#else
      #define SIMPLE_CLASS_EXPORT __declspec(dllimport)
#endif


要約すると:ダイナミックライブラリ自体は、アプリケーションのためのキーワード__declspec(dllexport)を使用する必要があります、あなたはダイナミックライブラリにエクスポートされた変数を使用しない場合は、キーワード__declspec(dllimport)もダイナミックライブラリの通常の使用を確保できる使用しないで、実際には、それはアプリケーションが上記のMSDN引用と同じ理由で、キーワード__ declspec(dllimport)を使用していることが推奨されています。

 動的ライブラリと静的ライブラリの共存

    また、プログラムで動的ライブラリと静的ライブラリの両方を提供する必要があり、その両方が1つのヘッダーファイルを使用する場合があります。キーワードの使い方の衝突を解決するために、以下のようなマクロ定義を使用することが推奨されます。

#ifdefined DLL_EXPORTS
    #ifdefined INSIDE_DLL
         #define SIMPLE_CLASS_EXPORT__declspec(dllexport)
    #else
        #define SIMPLE_CLASS_EXPORT__declspec(dllimport)
    #endif
#else
      #define SIMPLE_CLASS_EXPORT
#endif


ダイナミック・ライブラリ自体には、マクロ DLL_EXPORTS と INSIDE_DLL を定義する必要があります。 ダイナミック・ライブラリを使用するアプリケーションは、マクロ DLL_EXPORTS を定義しています。

静的ライブラリの場合は、DLL_EXPORTSを定義する必要はなく、静的ライブラリを使用するアプリケーションでは確実に定義する必要があります。

このように定義することで、動的ライブラリと静的ライブラリの両方を同じヘッダーファイルを使ってエクスポートすることができます。