お茶漬けびより

"あなたに教わったことを、噛んでいるのですよ" 五等分の花嫁 7巻 「最後の試験が五月の場合」より

Visual Studio で 動的ライブラリ(DLL)を作成する

f:id:pickles-ochazuke:20170705153246j:plain

自分へのメモ書き(上の画像に意味はないです)。

ライブラリを自分で作ったことがなかったので、ちょいと作ってみることに。
Visual Studio は 2017 です。あと C++ で書きます。

DLL プロジェクトの作成

まず、いつも通り Visual Studio を起動して、新しいプロジェクトを作成します。
選ぶプロジェクトの種類ですが、Win32 コンソールアプリケーション を選びます。
で、名前はてきとうで構いません。
簡単で打ち間違いにくい名前にするといいかもしれません。ここでは、DLLTest にしました。

f:id:pickles-ochazuke:20170704231404p:plain

OK > 次へ > と進み、アプリケーションの種類では、DLL を選びます。
他は、何もいじらなくてOKです。完了を押します。

f:id:pickles-ochazuke:20170704231409p:plain

するとプロジェクトが作成され、ソリューションエクスプローラソースファイルの下には、dllmain.cpp, DLLTest.cpp, stdafx.cpp があり、ヘッダーファイルには、stdafx.h, targetver.h があります。

f:id:pickles-ochazuke:20170704231751p:plain

それぞれ開くと、中にコメントが書かれているので、読んでおくといいかもしれません。まぁ触るのは、DLLTest.cpp だけなのですが。

DLL の実装

では、ライブラリを作っていきます。まず、ヘッダーファイルにファイルを追加します。ここは、いつも通り新しいクラスを追加するときと同じように作れば良いです。ファイル名も同じように自由です。ここでは、DLLTest.hにしました。
そして、先頭に以下を書きます。

#ifdef DLLTEST_EXPORTS
#define DLLTEST_API __declspec(dllexport)
#else
#define DLLTEST_API __declspec(dllimport)
#endif

ここで注意して欲しいのは、ifdef DLLTEST_EXPORTS です。これは、プロジェクト名によって異なりますので注意です。新しいプロジェクトを DLL として作成したときに、Visual Studio 側が勝手に定義してくれます。その名前は、プロジェクト名(全て大文字)_EXPORTS となります。今回、プロジェクト名は、DLLTest だったので、DLLTEST_EXPORTS となるわけです。

あとは、この下にいつものようにクラスを書いていきます。今回は、以下のように書いてみました。

namespace DLLTest {
    class HelloWorld {
    public:
        int huga;
        DLLTEST_API HelloWorld();
        static DLLTEST_API void hello();
        DLLTEST_API void world();
    private:
        int hoge = 0;
    };
}

各関数の手前に、DLLTEST_API があります。先頭行で書いた define です。DLLTEST_EXPORTS が定義されているので中身は、__declspec(dllexport) となるはずです。__declspec(dllexport)__declspec(dllimport) の違いは、ちゃんと調べていないですが、DLL を作成するときは、dllexport で、 DLL を利用するときは、dllimport だと判断しています。

変数には付けなくても問題ないようです(ここら辺のことは、どこを見たら分かるんですかね……)。

次に、DLLTest.cpp に書いていきます。全文を載せています。

#include "stdafx.h"
#include "DLLTest.h"
#include "iostream"

namespace DLLTest {
    HelloWorld::HelloWorld()
        : hoge(32)
    {  
        std::cout << "HelloWorld " << hoge << std::endl;
    }

    void HelloWorld::HelloWorld::hello()
    {
        std::cout << "Hello";
        return;
    }

    void HelloWorld::HelloWorld::world()
    {
        std::cout << "World" << std::endl;
        return;
    }
}

こちらは、とくに変わらずいつも通りに書いてしまえば問題ありません。気をつけるのは、stdafx.h は一番最初にインクルードする必要があることです。原因はよく分かっていないですが、他のインクルードの後だと、ビルドが通りませんでした。

ビルドをして成功したら、DLLTest のフォルダ下にある Debug フォルダに DLLTest.dll があると思います。

おわり

以上で DLL の作成は完了です。まだまだ何となくで作っていますが、少しずつ理解を深めていこうと思います。そのときに分かったことがあれば、また記事にしたいですね。何か参考になりそうな資料を教えていただければ幸いです。

次回は、作成した DLL を使ってみたいと思います。

pickles-ochazuke.hatenablog.com

以下を参考にしました。

https://msdn.microsoft.com/ja-jp/library/ms235636.aspx
https://msdn.microsoft.com/ja-jp/library/3y1sfaz2.aspx