Eternal Windows
DLL / DLLの利用

今回は、前節で作成したDLLの関数を呼び出すプログラムを作成します。 そのためには、EXEをビルドするにあたって何が必要なのかを考える必要があります。 EXEはDLLの関数を呼び出すわけですから、DLLの関数をコード中に書くことになります。 そのため、DLLの関数を定義したヘッダーファイルが必要です。 よって、前節で作成したmydll.hをEXEの開発環境に追加し、 コードではmydll.hをインクルードすることになるでしょう。

本章の最初の節でも述べましたが、ヘッダーファイルにDLLの関数の定義があったとして その関数を正しく呼び出したとしても、ビルドが成功するとは限りません。 リンカは、その関数が本当にDLLに存在するのか確かめるべく、 インポートライブラリをチェックすることを思い出してください。 そのため、DLLの作成の際に一緒に作成されたインポートライブラリも、 EXEの開発環境に移動させる必要があります。 しかし、DLL事体は開発環境に移動させておく必要はありません。 DLLが必要になるのはEXEを起動するときですから、ビルドにDLLは必須ではありません。 しかし、ビルドが成功したらテストのためにEXEを起動するでしょうから、 インポートライブラリと共にDLLも移動させておくべきでしょう。

以上の事を行うと、EXEの環境は以下のようになると思います。

見て分かるように、mydll.h、mydll.lib、mydll.dllが存在しています。 mydll.hはディレクトリに置くだけでなく、 実際にプロジェクトに追加するのを忘れないでください。 また、EXEを起動するときに絶対に必要となるのは、EXEとDLLのみです。 インポートライブラリは、プログラムのリンク時に必要となるものですから、 アプリケーションを公開するときに同梱する必要はありません。

今回のプログラムは、前節で作成したmydll.dllのSwap関数を呼び出します。 mydll.hの内部は、前節で示したものと同一です。

#include <windows.h>
#include "mydll.h"

#pragma comment (lib, "mydll.lib")

int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR lpszCmdLine, int nCmdShow)
{
	int   a, b;
	TCHAR szBuf[256];
	
	a = 1;
	b = 2;

	Swap(&a, &b);

	wsprintf(szBuf, TEXT("a = %d, b = %d"), a, b);
	MessageBox(NULL, szBuf, TEXT("OK"), MB_OK);

	return 0;
}

#pragmaディレクティブで、リンカにmydll.libをリンクするよう指示しているのが重要です。 リンカは、自身が検索するパスを定義していますが、 mydll.libはそのパスに位置していません。 しかし、#pragmaディレクティブを使うことによりリンカは、 プロジェクトのディレクトリを検索してくれのるで、リンクは成功するのです。

コードはSwapを呼び出すという至って単純なものですが、 なかなか感動するものがあるのではないでしょうか。 関数をDLLに実装する方法とそれを呼び出す方法を覚えるというのは、 それだけでかなりのレベルアップといえるはずです。 大規模なプログラムの開発では、DLLによる開発作業の分担は珍しくありません。

明示的リンクによる呼び出し

今回は自作のDLLに暗黙的リンクを行いましたが、 DLLのリンクにはLoadLibraryを使用した明示的リンクもあります。 この方法を使用すればインポートライブラリも必要ありませんし、 DLLが存在しないことでエラーのダイアログが表示されることもなくなります。

#include <windows.h>

typedef void (*LPFNSWAP)(int *, int *);

int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR lpszCmdLine, int nCmdShow)
{
	int      a, b;
	TCHAR    szBuf[256];
	HMODULE  hmod;
	LPFNSWAP lpfnSwap;

	hmod = LoadLibrary(TEXT("mydll.dll"));
	if (hmod == NULL)
		return 0;

	lpfnSwap = (LPFNSWAP)GetProcAddress(hmod, "Swap");
	if (lpfnSwap == NULL) {
		FreeLibrary(hmod);
		return 0;
	}

	a = 1;
	b = 2;

	lpfnSwap(&a, &b);

	wsprintf(szBuf, TEXT("a = %d, b = %d"), a, b);
	MessageBox(NULL, szBuf, TEXT("OK"), MB_OK);
	
	FreeLibrary(hmod);

	return 0;
}

LoadLibraryによってmydll.dllをロードし、これが成功した場合はGetProcAddressでSwapのアドレスを取得します。 アドレスを取得すれば、後は暗黙的リンクの際と同じように関数を呼び出すことができます。



戻る