はじめに
Visual Studio 2015 CommunityでDLLを作成して、コンソールアプリケーションからDLLを動的読み込みして、関数を実行してみたいと思います。
ソフトバンククリエイティブ
売り上げランキング: 15,556
環境
- Windows 8.1
- Visual Studio 2015 Community
DLLの作成
Visual Studio 2015であたらしいプロジェクトを作成する前に、テンプレートをダウンロードします。「Install Visual C++ 2015 Tool ...」を選択してテンプレートをインストールします。
Win32コンソールが表示されたら選択します。
今回は、渡されたアドレスに対して「Hello World!」と書き込む関数を作ってみます。(GetHello関数)
GetHello関数のサンプルプログラムは、以下のようなコードです。
#include "stdafx.h" int GetHello(char *message) { memcpy(message, "Hello World!", 12); return 0; }
続いて、作成したGetHello関数は、外部に対して公開しなければならないため、.defファイルを作ります。
defファイルの中には、以下のような定義を行います。LIBRARYにはDLLの名前を指定し、EXPORTSセクションで外部に対して公開する関数名を指定します。
LIBRARY HelloWorld
EXPORTS
GetHello @1
作成したdefファイルは、「リンカ」→「入力」→「モジュール定義」のところで、ファイル名を指定します。
ソリューションをリビルドして、DLLができたら、以下のコマンドを実行して関数が見えるかどうかを確認します。
C:\Program Files\Microsoft Visual Studio 14.0\VC\bin\dumpbin.exe /exports HelloWorld.dll
GetHello関数が参照できればOKです。
DLLのロードと関数の呼び出し
DLLの読み込みには、LoadLibrary関数を使います。DLLが見つからない場合などは、ハンドルがNULLで返ってくるので、エラーハンドリングを行います。
// DLLのロード HMODULE hModule = LoadLibrary(_T("HelloWorld.dll")); if (hModule == NULL) { printf("%s", "DLLのロードに失敗しました。"); return 0; }
LoadLibraryが正常にいったら、次に呼び出す関数のアドレスを取得する必要があります。関数のアドレスを取得するには、GetProcAddress関数を使います。
GetProcAddressに失敗した場合は、必ずFreeLibraryを呼び出し、DLLを解放します。
// 関数のアドレス取得 FUNC lpFunc = (FUNC)GetProcAddress(hModule, "GetHello"); if (lpFunc == NULL) { printf("%s", "関数のアドレス取得に失敗しました。"); FreeLibrary(hModule); return 0; }
GetHello関数の呼び出すには、まずtypedefでGetHello関数を定義します。
typedef int (*FUNC)(char *);
続いて、GetProcAddressから取得したアドレスに対して、引数を渡します。
// 関数の呼び出し int ret = (*lpFunc)(tmp); if (ret != 0) { printf("%s", "関数の呼び出しに失敗しました。"); FreeLibrary(hModule); return 0; }
DLLを読み込むサンプルプログラム
#include "stdafx.h" #include <Windows.h> #include <conio.h> typedef int(*FUNC)(char *); int _tmain(int argc, _TCHAR* argv[]) { char tmp[12 + 1]; memset(tmp, 0, sizeof(tmp)); // DLLのロード HMODULE hModule = LoadLibrary(_T("HelloWorld.dll")); if (hModule == NULL) { printf("%s", "DLLのロードに失敗しました。"); return 0; } // 関数のアドレス取得 FUNC lpFunc = (FUNC)GetProcAddress(hModule, "GetHello"); if (lpFunc == NULL) { printf("%s", "関数のアドレス取得に失敗しました。"); FreeLibrary(hModule); return 0; } // 関数の呼び出し int ret = (*lpFunc)(tmp); if (ret != 0) { printf("%s", "関数の呼び出しに失敗しました。"); FreeLibrary(hModule); return 0; } // DLLの解放 FreeLibrary(hModule); printf("%s\n", tmp); _getch(); return 0; }