次の方法で共有


TN011: MFC を DLL の一部として使用する

このノートでは、通常の 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 を使用できるようになります。

こちらも参照ください

番号別テクニカル ノート
カテゴリ別テクニカル ノート