と思ったが、全然そんなことはなかった。
主に参考にしたサイト
これらを参考に実装していきます。
本ページの目的を以下に示します。
- DLLを明示的に呼び出す
- DLLからHello Worldする
メインソースファイル
#include <stdio.h> #include <windows.h> #include "./util.h" int main(int argc, char* argv[]) { (void)argc; (void)argv; // Load DLL. HINSTANCE hDLL = LoadLibrary(L"util.dll"); if (hDLL == NULL) { fwprintf(stderr, L"Failed to load DLL\n"); return 1; } // Load DLL function. void (*func)() = NULL; func = (void (*)())GetProcAddress(hDLL, "HelloWorld"); if (func == NULL) { fwprintf(stderr, L"Failed to get function\n"); } else { func(); } // Release DLL. FreeLibrary(hDLL); return 0; }
- hDLL
今回作成したDLLへのインスタンスハンドルです。 - LoadLibrary、FreeLibrary
それぞれ、DLLのロードと解放を行う関数です。 - GetProcAddress
DLLから関数のアドレスを取得します。
DLLのソースファイル
DLLのヘッダファイル
#define DLLAPI extern "C" __declspec(dllexport) #include "./util.h" #include <stdio.h> DLLAPI void HelloWorld() { wprintf(L"Hello World!\n"); }
#ifndef _UTIL_H_ #define _UTIL_H_ #include <stdio.h> #ifndef DLLAPI #define DLLAPI extern "C" __declspec(dllimport) #endif DLLAPI void HelloWorld(); #endif // _UTIL_H_
- #define DLLAPI extern "C" __declspec(dllexport)
DLLAPIマクロを、DLLのソースファイルではこのように定義しておきます。
ヘッダファイルをインクルードする前に定義するのがポイントです。 - #define DLLAPI extern "C" __declspec(dllimport)
DLLAPIマクロを、DLLのヘッダファイルではこのように定義しておきます。 - HelloWorld
DLLに実装する、ハローワールドする関数です。 - DLLMainは?
今回のケースは簡単なので、書かなくても大丈夫です。
作りたいプログラムによっては、あると便利な場合もあるのでしょう。
DLLAPIマクロのからくりについては、参考サイトの方で詳しく解説されています。
TARGET = main.exe PDB = main.pdb MAP = main.map RES = SRC = main.cc util.cc OBJ = $(OBJDIR)\main.obj DLL = util.dll OBJDIR = build CC = "$(VCINSTALLDIR)\cl.exe" LINK = "$(VCINSTALLDIR)\link.exe" CPPFLAGS = /nologo /W4 /Zi /O2 /MT /EHsc /Fd"$(TMPDIR)/" /DUNICODE /D_UNICODE \ /DDEBUG LFLAGS = "kernel32.lib" "user32.lib" "gdi32.lib" "winspool.lib" \ "comdlg32.lib" "advapi32.lib" "shell32.lib" "ole32.lib" \ "oleaut32.lib" "uuid.lib" "odbc32.lib" "odbccp32.lib" "libcmt.lib" \ /NOLOGO /SUBSYSTEM:CONSOLE /DEBUG ALL: $(TARGET) $(TARGET): $(OBJ) $(DLL) $(RES) $(LINK) $(LFLAGS) /OUT:$(TARGET) /PDB:"$(PDB)" /MAP:"$(MAP)" \ $(OBJ) $(RES) .cc{$(OBJDIR)}.obj: @[ -d $(OBJDIR) ] || mkdir $(OBJDIR) $(CC) $(CPPFLAGS) /Fo"$(OBJDIR)\\" /c $< .cc.dll: $(CC) $(CPPFLAGS) /LD $< clean: rm $(OBJ) $(TARGET) *.map *.pdb *.ilk *.obj *.lib *.dll *.exp
- SUBSYSTEM:CONSOLE
コンソールアプリケーションとしてビルドすることを、リンカオプションで設定します。 - .cc.dll
CCファイルからDLLファイルを作るルールを指定します。
clコンパイラでは、LDオプションを付けることでDLLを作れます。
DLLを含むプロジェクトのためのMakefileは初出ですが、.cc.dllのルールが加わったこと以外、あまり変わりませんね。
備考
意外とあっさりしていて驚いた。
DLLを扱ったことで、Windowsに対する理解が深まった気がする。
プロジェクト一式については、GitHubにも上げておきます。
0 件のコメント:
コメントを投稿
コメント表示は承認制に設定しています