目次
① MFCDllDialog.dll のロジック
MFCDllDialog.h
#pragma once
// DLLのエクスポート/インポート制御
#ifdef MFCDLLDIALOG_EXPORTS
#define MFCDLLDIALOG_API __declspec(dllexport) // DLLをエクスポートするための定義
#else
#define MFCDLLDIALOG_API __declspec(dllimport) // DLLをインポートするための定義
#endif
// DLLでエクスポートする関数
extern "C" MFCDLLDIALOG_API void MFCDllDialogShow();
MFCDllDialog.cpp
#include "pch.h"
#include "MFCDllDialog.h"
#include "DialogExample.h"
// DLLでエクスポートされる関数
extern "C" MFCDLLDIALOG_API void MFCDllDialogShow() {
CWinApp app; // MFCアプリケーションの初期化
DialogExample dlg; // ダイアログのインスタンス
dlg.DoModal(); // ダイアログをモーダル表示
}
DialogExample.h
#pragma once
#include "afxwin.h"
// MFC ダイアログクラス
class DialogExample : public CDialogEx {
public:
DialogExample();
enum { IDD = IDD_EXAMPLE_DIALOG }; // リソース ID
protected:
virtual void DoDataExchange(CDataExchange* pDX); // データと UI のリンク
DECLARE_MESSAGE_MAP()
};
リソースファイル(resource.h と .rc)
resource.h
:
#define IDD_EXAMPLE_DIALOG 1001 // ダイアログリソース ID
.rc
ファイル:
IDD_EXAMPLE_DIALOG DIALOGEX 0, 0, 200, 100
STYLE DS_SETFONT | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "MFCDllDialog Example"
FONT 8, "MS Shell Dlg", 0, 0, 0x1
BEGIN
DEFPUSHBUTTON "OK",IDOK,75,70,50,14
END
② MFCApplication.exe のロジック
MainForm.cpp
#include "pch.h"
#include "MainForm.h"
// DLL内の関数を指す関数ポインタ型を定義
typedef void (*MFCDllDialogShowFunc)();
// ダイアログ起動ボタンが押されたときの処理
void MainForm::OnLaunchDialogClicked() {
// MFCDllDialog.dll を動的にロード
HMODULE hModule = LoadLibrary(_T("MFCDllDialog.dll"));
if (hModule) { // DLLが正常にロードされた場合
// DLL内のMFCDllDialogShow関数を取得
MFCDllDialogShowFunc showFunc = (MFCDllDialogShowFunc)GetProcAddress(hModule, "MFCDllDialogShow");
if (showFunc) {
// 関数を呼び出してダイアログを表示
showFunc();
} else {
MessageBox(NULL, _T("MFCDllDialogShow関数が見つかりません"), _T("エラー"), MB_ICONERROR);
}
// DLLを解放
FreeLibrary(hModule);
} else {
MessageBox(NULL, _T("MFCDllDialog.dll が見つかりません"), _T("エラー"), MB_ICONERROR);
}
}
MainForm.h
#pragma once
#include "afxwin.h"
// MFC アプリケーションクラス
class MainForm : public CDialogEx {
public:
MainForm();
enum { IDD = IDD_MAIN_FORM }; // メインフォームのリソース ID
protected:
virtual void DoDataExchange(CDataExchange* pDX); // データと UI のリンク
afx_msg void OnLaunchDialogClicked(); // ボタンクリックのイベント
DECLARE_MESSAGE_MAP()
};
resource.h
#define IDD_MAIN_FORM 101
#define IDC_LAUNCH_BUTTON 1001
.rc ファイル
IDD_MAIN_FORM DIALOGEX 0, 0, 200, 100
STYLE DS_SETFONT | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "MFC Application"
FONT 8, "MS Shell Dlg", 0, 0, 0x1
BEGIN
PUSHBUTTON "ダイアログ起動",IDC_LAUNCH_BUTTON,50,50,100,20
END
MainForm.cpp のイベント登録
#include "pch.h"
#include "MainForm.h"
#include "resource.h"
MainForm::MainForm() : CDialogEx(IDD_MAIN_FORM) {}
void MainForm::DoDataExchange(CDataExchange* pDX) {
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(MainForm, CDialogEx)
ON_BN_CLICKED(IDC_LAUNCH_BUTTON, &MainForm::OnLaunchDialogClicked)
END_MESSAGE_MAP()
重要なポイント
- DLLの読み込みと解放
LoadLibrary
を使って動的にDLLを読み込み、FreeLibrary
で解放します。- 関数ポインタ (
GetProcAddress
) を使ってMFCDllDialogShow
を呼び出します。
- DLLとアプリケーションの連携
- DLL内の
MFCDllDialogShow
は、MFC ダイアログを表示する関数。 - アプリケーション側でDLLを動的に読み込み、必要なときだけ関数を実行します。
- DLL内の
- エラーハンドリング
- DLLが見つからない場合や、関数が取得できない場合にエラーメッセージを表示する処理を追加しています。

ヘッダーファイルをエクスポート側とインポート側で共通利用する場合
静的リンクと動的リンクの違い
- 静的リンク
- ライブラリファイル (
.lib
) とヘッダーファイル (.h
) をアプリケーションに組み込む形です。 - 実行時に外部DLLをロードする必要がありません。すべてが実行ファイルに埋め込まれます。
- リンカ設定で
.lib
ファイルを指定します。
- ライブラリファイル (
- 動的リンク
- 実行時にDLLファイル(例:
example.dll
)を読み込みます。 - リンカはDLLに対応するインポートライブラリ (
.lib
) を参照するか、動的にLoadLibrary
でDLLをロードします。 - 実行ファイル自体はDLLが必要で、DLLが見つからないとエラーになります。
- 実行時にDLLファイル(例:
リンカ設定に必要な項目
静的リンク
.h
ファイルと.lib
ファイルをプロジェクトに追加します。- リンカ設定で
.lib
を指定します。- 設定方法(Visual Studioの場合):
- プロジェクトのプロパティを開く。
- リンカー > 入力 > 追加の依存ファイルに
.lib
ファイルを指定します。
- 設定方法(Visual Studioの場合):
__declspec(dllexport)
と__declspec(dllimport)
の役割- 静的リンクでは、DLL自体をロードしませんが、
.lib
を通じてDLL内のシンボルを参照します。 __declspec(dllimport)
を指定すると、コンパイラがインポートライブラリの記述をもとに効率的にリンクを行います。
- 静的リンクでは、DLL自体をロードしませんが、
動的リンク
- 実行時に
LoadLibrary
とGetProcAddress
を使用してDLLを読み込みます。 .lib
ファイルは不要です。- リンカ設定は不要で、DLLを直接動的にロードします。
静的リンクの場合のコード例
以下は、静的リンクの場合のコード例です。
エクスポート側(DLL側)
#pragma once
#ifdef MYLIB_EXPORTS
#define MYLIB_API __declspec(dllexport) // DLLをエクスポート
#else
#define MYLIB_API __declspec(dllimport) // DLLをインポート
#endif
extern "C" MYLIB_API int Add(int a, int b);
MyLib.cpp
#include "MyLib.h"
extern "C" MYLIB_API int Add(int a, int b) {
return a + b;
}
ビルドすると、以下のファイルが生成されます:
MyLib.dll
(実行時に使用)MyLib.lib
(静的リンク時に使用)
インポート側(アプリケーション側)
Main.cpp
#include <iostream>
#include "MyLib.h" // DLLのヘッダーファイル
int main() {
int result = Add(3, 5); // 静的リンクでAdd関数を使用
std::cout << "Result: " << result << std::endl;
return 0;
}
プロジェクト設定
- リンカー > 入力 > 追加の依存ファイル に
MyLib.lib
を指定します。
動的リンクの場合のコード例
エクスポート側(DLL側)
同じです。__declspec(dllexport)
を使います。
インポート側(アプリケーション側)
Main.cpp
#include <iostream>
#include <Windows.h>
typedef int (*AddFunc)(int, int);
int main() {
// DLLをロード
HMODULE hModule = LoadLibrary("MyLib.dll");
if (!hModule) {
std::cerr << "DLLが見つかりません" << std::endl;
return 1;
}
// 関数ポインタを取得
AddFunc Add = (AddFunc)GetProcAddress(hModule, "Add");
if (!Add) {
std::cerr << "Add関数が見つかりません" << std::endl;
FreeLibrary(hModule);
return 1;
}
// 関数を使用
int result = Add(3, 5);
std::cout << "Result: " << result << std::endl;
// DLLを解放
FreeLibrary(hModule);
return 0;
}
まとめ
- 静的リンクでは、
.lib
ファイルを使用し、リンカで設定を行います。ヘッダーファイルには__declspec(dllimport)
が必要です。 - 動的リンクでは、
LoadLibrary
とGetProcAddress
を使用し、__declspec(dllimport)
は不要です。 - 静的リンクと動的リンクの違いを正確に把握し、用途に応じて使い分ける必要があります。