Version 15.09
DLLを作る!
「前回はスタティックリンクライブラリを使ってみました」
『ってことは!?』
「今回はダイナミックリンクライブラリ、つまり DLL を作ってみます」
『おお!! なんか DLL 作れるってすんごくレベル高い気がする!!』
「ま、結構難しいからね。というわけで、一番最初は簡単な方法で使ってみ
ます」
『簡単な方法?』
「そう、必要なファイルが最初から作られてる状態のプロジェクトを作って
それを試してみます」
『……ってことは、その次は、その必要なファイルってのを自分で作れるよ
うにする、ってことね……』
「そういうこと。でも DLL はその必要なファイルを作るとことかがすんご
く大変だったりするから、まずは作って使えるのが大事、ってことで」
『なんか最初から脅されてヤダなぁ……』
「ま、 DLL は実際にかなりレベル高い分野だから、できるようになってお
くと後々いいと思うよ」
『ってゆーかできないとダメ?』
「まぁね。さて、ではまずプロジェクトを作ります。メニューの
【新規作成】ダイアログで【プロジェクト】タブを開いて」
『いつものね』
「【Win32 Dynamic-Link Library】を選んで、プロジェクト名は
DLLTestEasy で」
『 Easy ……ね。あれ、この中に【MFC AppWizard (dll)】ってのもあるけ
ど、こっちは違うの?』
「そっちは MFC を使う DLL 。今回、呼び出す側はこれまでのと同じ
BuildTest を使うから」
『 BuildTest って MFC 使ってなかったからそっちじゃないのね』
「そういうこと。話を戻して、プロジェクト名を入れたら」
『 OK っと、ん』
・空の DLL プロジェクト
・単純な DLL プロジェクト
・シンボルをエクスポートする DLL
『って3つある』
「一番下の【シンボルをエクスポートする DLL 】を選んで。これが一番簡
単なのだから」
『これを選ばないと、必要なファイルが作られない?』
「そういうこと。【シンボルをエクスポートする DLL 】を選べば、 VC++
が必要なファイルを作ってくれます」
『んじゃそれで』
「プロジェクトを作ったら、ワークスペースの【FileView】を見て」
Source Files
- DLLTestEasy.cpp
- StdAfx.cpp
Header Files
- DLLTestEasy.h
- StdAfx.h
『お、ソースファイルとヘッダーファイルができてる』
「まずソースファイル」
// DLLTestEasy.cpp : DLL アプリケーション用のエントリ ポイントを定義します。
//
#include "stdafx.h"
#include "DLLTestEasy.h"
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
// これはエクスポートされた変数の例です。
DLLTESTEASY_API int nDLLTestEasy=0;
// これはエクスポートされた関数の例です。
DLLTESTEASY_API int fnDLLTestEasy(void)
{
return 42;
}
// これはエクスポートされたクラスのコンストラクタです。
// クラスの定義については DLLTestEasy.h を参照してください。
CDLLTestEasy::CDLLTestEasy()
{
return;
}
『……なんか目眩がする……』
「関数やクラスが色々あるけど、今回のテストでは fnDLLTestEasy() だけ
使います。なので」
// これはエクスポートされた関数の例です。
DLLTESTEASY_API int fnDLLTestEasy(void)
{
OutputDebugString( "fnDLLTestEasy()" );
return 42;
}
『あ、デバッグ出力するのね』
「次にヘッダーファイル」
// DLLTestEasy.h
// 以下の ifdef ブロックは(略)
#ifdef DLLTESTEASY_EXPORTS
#define DLLTESTEASY_API __declspec(dllexport)
#else
#define DLLTESTEASY_API __declspec(dllimport)
#endif
// このクラスは DLLTestEasy.dll からエクスポートされます
class DLLTESTEASY_API CDLLTestEasy {
public:
CDLLTestEasy(void);
// TODO: この位置にメソッドを追加してください。
};
extern DLLTESTEASY_API int nDLLTestEasy;
DLLTESTEASY_API int fnDLLTestEasy(void);
『こ、こっちも目眩がするっ……!』
「こちらは修正しなくていいです。とりあえずビルドして」
『ほいビルド』
--------------------構成: DLLTestEasy - Win32 Debug-----------------
コンパイル中...
StdAfx.cpp
コンパイル中...
DLLTestEasy.cpp
リンク中...
ライブラリ Debug/DLLTestEasy.lib と
オブジェクト Debug/DLLTestEasy.exp を作成中
DLLTestEasy.dll - エラー 0、警告 0
『んーと』
DLLTestEasy.lib
DLLTestEasy.exp
DLLTestEasy.dll
『の3つのファイルができたみたい。あ! lib ファイルがある!』
「そう、 DLL を作ったときにもライブラリファイルができるんです。ただ
し、スタティックリンクライブラリと違って、プログラムの本体は入ってま
せん」
『そりゃそうだよね、それって DLL に入ってるんでしょ?』
「そういうこと。 DLL の場合、プログラムをコンパイルしたものは DLL に
入ってます」
『 DLL がオブジェクトファイル代わりってことね』
「さて、この DLL を使います。でも実はスタティックリンクライブラリの
時とほとんど同じ」
『え、そうなの? なんかすごく難しそうだったのに』
「これまでの BuildTest を使って、さっきの DLL にあった
fnDLLTestEasy() を 呼び出します。まず Main.cpp をこう修正して」
// Main.cpp
#include <Windows.h>
#include "DLLTestEasy.h"
int WINAPI WinMain
( HINSTANCE p_hInstance
, HINSTANCE p_hPrevInstance
, LPSTR p_pchCmdLine
, int p_iCmdShow
)
{
fnDLLTestEasy();
return 0;
}
『あ、 fnDLLTestEasy() 呼んでる』
「それと、ヘッダーファイル
プログラムの修正はこれだけ。次は設定。と、その前に、 DLLTestEasy
のプロジェクトフォルダを」
D:\Program\DLLTestEasy
「とします。あとはスタティックリンクライブラリと同じ。BuildTest の
メニューの【プロジェクト】-【設定】ダイアログを開いて」
『で、【C/C++】タブの【プリプロセッサ】ページの
【インクルードファイルのパス】に』
D:\Program\DLLTestEasy
『って書いて、【リンク】タブの【追加ライブラリのパス】に』
D:\Program\DLLTestEasy\Debug
『ってして、さらに【オブジェクト/ライブラリ モジュール】の右端に
DLLTestEasy.lib を追加して、ビルドして実行!』
「あ」
ダイナミックリンク ライブラリ DLLTestEasy.dll が指定されたパス
----に見つかりませんでした。
『なんでー!?』
「 DLLTestEasy.dll を BuildTest.exe のある BuildTest\Debug
フォルダに置けば動くよ」
『あー、そっか DLL だもんね』
「というわけで詳しいことは次回に!」
/*
Preview Next Story!
*/
『とりあえず使えたけど、何がなにやら』
「そう、本当はいろんな手続きが必要なんだけど」
『そういうのも勝手にしてくれてるってこと?』
「そういうこと。 #ifdef マクロのとことか」
『というわけで次回』
< Version 15.10 エクスポートとインポート >
「につづく!」
『出力と入力?』
「単語そのものは分かりやすいんだけどね……」