このノートでは、通常の MFC DLL について説明します。MFC ライブラリを Windows ダイナミック リンク ライブラリ (DLL) の一部として使用できます。 Windows DLL とその構築方法を理解していることを前提としています。 MFC ライブラリの拡張機能を作成できる MFC 拡張 DLL の詳細については、「 MFC の DLL バージョン」を参照してください。
DLL インターフェイス
通常の MFC DLL は、アプリケーションと DLL の間のインターフェイスが C のような関数または明示的にエクスポートされたクラスで指定されていることを前提としています。 MFC クラス インターフェイスはエクスポートできません。
DLL とアプリケーションの両方で MFC を使用する場合は、MFC ライブラリの共有バージョンを使用するか、ライブラリのコピーに静的にリンクするかを選択できます。 アプリケーションと DLL の両方で、MFC ライブラリの標準バージョンのいずれかを使用できます。
通常の MFC DLL には、いくつかの利点があります。
DLL を使用するアプリケーションは MFC を使用する必要はありません。また、Visual C++ アプリケーションである必要はありません。
MFC に静的にリンクする通常の MFC DLL では、DLL のサイズは、使用およびリンクされている MFC および C ランタイム ルーチンにのみ依存します。
MFC に動的にリンクする通常の MFC DLL では、MFC の共有バージョンを使用するメモリの節約が重要になる可能性があります。 ただし、共有 DLL である Mfc<version>.dll および Msvvcrt<version>.dllを DLL と共に配布する必要があります。
DLL の設計は、クラスの実装方法とは無関係です。 DLL デザインは、必要な API にのみエクスポートします。 その結果、実装が変更された場合でも、通常の MFC DLL は引き続き有効です。
MFC に静的にリンクする通常の MFC DLL では、DLL とアプリケーションの両方で MFC を使用する場合、DLL とは異なるバージョンの MFC を必要とするアプリケーションに問題はありません。その逆も同様です。 MFC ライブラリは各 DLL または EXE に静的にリンクされているため、使用しているバージョンに関する質問はありません。
API の制限事項
MFC の一部の機能は、技術的な制限のため、またはこれらのサービスが通常アプリケーションによって提供されるため、DLL バージョンには適用されません。 MFC の現在のバージョンでは、適用できない唯一の関数は CWinApp::SetDialogBkColor
。
DLL のビルド
MFC に静的にリンクする通常の MFC DLL をコンパイルする場合は、シンボル _USRDLL
と _WINDLL
を定義する必要があります。 DLL コードは、次のコンパイラ スイッチを使用してコンパイルする必要もあります。
/D_WINDLL は、コンパイルが DLL 用であることを示します
/D_USRDLL は、通常の MFC DLL をビルドしていることを指定します
また、MFC に動的にリンクする通常の MFC DLL をコンパイルするときに、これらのシンボルを定義し、これらのコンパイラ スイッチを使用する必要があります。 さらに、シンボル _AFXDLL
を定義し、DLL コードを次のようにコンパイルする必要があります。
- /D_AFXDLL は、MFC に動的にリンクする通常の MFC DLL を構築することを指定します。
アプリケーションと DLL の間のインターフェイス (API) を明示的にエクスポートする必要があります。 インターフェイスを低帯域幅に定義し、可能な場合は C インターフェイスのみを使用することをお勧めします。 直接 C インターフェイスは、より複雑な C++ クラスよりも保守が容易です。
C ファイルと C++ ファイルの両方に含めることができる個別のヘッダーに API を配置します。 例については、MFC Advanced Concepts サンプル DLLScreenCap のヘッダー ScreenCap.h を参照してください。 関数をエクスポートするには、モジュール定義ファイルの EXPORTS
セクションに関数を入力します (.DEF) を使用するか、関数定義に __declspec(dllexport)
を含めます。
__declspec(dllimport)
を使用して、これらの関数をクライアント実行可能ファイルにインポートします。
MFC に動的にリンクする標準 MFC DLL 内のすべてのエクスポートされた関数の先頭に、AFX_MANAGE_STATE マクロを追加する必要があります。 このマクロは、現在のモジュールの状態を DLL の状態に設定します。 このマクロを使用するには、DLL からエクスポートされた関数の先頭に次のコード行を追加します。
AFX_MANAGE_STATE(AfxGetStaticModuleState( ))
WinMain -> DllMain
MFC ライブラリは、標準的な MFC アプリケーションと同様に CWinApp 派生オブジェクトを初期化する標準的な Win32 DllMain
エントリ ポイントを定義します。 一般的な MFC アプリケーションと同様に、すべての DLL 固有の初期化を InitInstance メソッドに配置します。
アプリケーションがメイン メッセージ ポンプを所有しているため、 CWinApp::Run メカニズムは DLL には適用されないことに注意してください。 DLL にモードレス ダイアログが表示される場合、または独自のメイン フレーム ウィンドウがある場合、アプリケーションのメイン メッセージ ポンプは 、CWinApp::P reTranslateMessage を呼び出す DLL エクスポート ルーチンを呼び出す必要があります。
この関数の使用については、DLLScreenCap サンプルを参照してください。
MFC が提供するDllMain
関数は、DLL がアンロードされる前に、CWinApp
から派生したクラスの CWinApp::ExitInstance メソッドを呼び出します。
DLL のリンク
MFC に静的にリンクする通常の MFC DLL では、DLL を Nafxcwd.lib または Nafxcw.lib にリンクし、Libcmt.lib という名前の C ランタイムのバージョンとリンクする必要があります。 これらのライブラリは事前に構築されており、Visual C++ セットアップの実行時に指定してインストールできます。
サンプル コード
完全なサンプルについては、MFC Advanced Concepts サンプル プログラム DLLScreenCap を参照してください。 このサンプルでは、次のような興味深い点に注意してください。
DLL のコンパイラ フラグとアプリケーションのコンパイラ フラグは異なります。
リンク行と .DLL 用の DEF ファイルとアプリケーション用のファイルは異なります。
DLL を使用するアプリケーションが C++ である必要はありません。
アプリケーションと DLL の間のインターフェイスは、C または C++ で使用できる API であり、DLLScreenCap.def を使用してエクスポートされます。
次の例は、MFC に静的にリンクする通常の MFC DLL で定義されている API を示しています。 この例では、宣言は C++ ユーザーの extern "C" { }
ブロックで囲まれています。 これにはいくつかの利点があります。 まず、C++ 以外のクライアント アプリケーションで DLL API を使用できるようにします。 次に、C++ 名のマングリングがエクスポートされた名前に適用されないため、DLL のオーバーヘッドが軽減されます。 最後に、明示的に .名前のマングリングを気にすることなく(序数でエクスポートするための)DEFファイル。
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
struct TracerData
{
BOOL bEnabled;
UINT flags;
};
BOOL PromptTraceFlags(TracerData FAR* lpData);
#ifdef __cplusplus
}
#endif
API によって使用される構造体は MFC クラスから派生せず、API ヘッダーで定義されます。 これにより、DLL とアプリケーション間のインターフェイスの複雑さが軽減され、C プログラムで DLL を使用できるようになります。