MFC と動的にリンクされるレギュラー DLL
MFC と動的にリンクするレギュラー DLL は、MFC を内部的に使用します。このレギュラー DLL のエクスポート関数は、MFC、非 MFC のどちらの実行可能ファイルからも呼び出すことができます。名前からもわかるように、この種の DLL は MFC のダイナミック リンク ライブラリ バージョン (MFC の共有バージョン) を使ってビルドされます。通常、関数は C 言語の標準インターフェイスを使ってレギュラー DLL からエクスポートされます。
MFC と動的にリンクする標準 DLL 中のエクスポートされるすべての関数の先頭に AFX_MANAGE_STATE マクロを追加して、現在のモジュール ステートを DLL のモジュール ステートに設定する必要があります。これは、DLL からエクスポートされる関数の先頭に次のコード行を追加して行います。
AFX_MANAGE_STATE(AfxGetStaticModuleState( ))
MFC と動的にリンクされるレギュラー DLL の特徴は、以下のとおりです。
Visual C++ 4.0 で新たに導入された DLL です。
クライアントの実行可能ファイルは、DLL を使用できる任意の言語 (C、C++、Pascal、Visual Basic など) で記述できます。MFC アプリケーションでなくてもかまいません。
静的にリンクされるレギュラー DLL とは異なり、MFC DLL と動的にリンクされます。MFC DLL は、MFC の共有 DLL とも呼ばれます。
この種の DLL にリンクされる MFC インポート ライブラリは、MFC DLL を利用するアプリケーションや拡張 DLL で使われるものと同じもので、MFCxx(D).lib です。
MFC と動的にリンクされるレギュラー DLL には、以下の必要条件があります。
MFC DLL と動的にリンクされる実行可能ファイルと同じく、_AFXDLL を定義してコンパイルされます。ただし、MFC と静的にリンクされるレギュラー DLL と同じく、_USRDLL も定義されます。
CWinApp 派生クラスをインスタンス化します。
MFC から提供される DllMain を使用します。通常の MFC アプリケーションと同じく、DLL 固有のすべての初期化コードを InitInstance メンバー関数に配置し、終了コードを ExitInstance メンバー関数に配置します。
MFC と動的にリンクされるレギュラー DLL では、MFC のダイナミック リンク ライブラリ バージョンを使用するので、現在のモジュール状態を DLL 用に明示的に設定する必要があります。そのためには、DLL からエクスポートされるすべての関数の先頭で、AFX_MANAGE_STATE マクロを使用します。
レギュラー DLL には、MFC アプリケーションの場合と同じく、CWinApp 派生クラスと、そのアプリケーション クラスの 1 つのオブジェクトの存在が必要です。ただし、アプリケーションの CWinApp オブジェクトはメイン メッセージ ポンプを備えていますが、DLL の CWinApp オブジェクトは備えていません。
CWinApp::Run の機構は DLL では使用できません。これは、アプリケーションがメイン メッセージ ポンプを所有しているためです。DLL 側でモードレス ダイアログを開いたり、独自のメインフレーム ウィンドウを備える場合には、まず DLL によりエクスポートされたルーチンをアプリケーションのメイン メッセージ ポンプから呼び出して、次にここから CWinApp::PreTranslateMessage メンバー関数を呼び出す必要があります。
DLL 固有の初期化処理はすべて、通常の MFC アプリケーションの場合と同じように、CWinApp::InitInstance メンバー関数で設定します。DLL がアンロードされる場合は、あらかじめ CWinApp 派生クラスの CWinApp::ExitInstance メンバー関数が DllMain 関数の提供する MFC から呼び出されます。
作成したアプリケーションと共に、共有 DLL MFCx0.dll と Msvcr*0.dll (または同様のファイル) を配布する必要があります。
MFC と動的にリンクされる DLL は、MFC と静的にリンクすることはできません。アプリケーションは、その他の DLL と同じく、MFC と動的にリンクされるレギュラー DLL にリンクされます。
シンボルは、通常、標準 C インターフェイスを使ってレギュラー DLL からエクスポートされます。レギュラー DLL からエクスポートされた関数の宣言は、次のようになります。
extern "C" __declspec(dllexport) MyExportedFunction( );
レギュラー DLL 内のメモリ割り当てはすべて、DLL の範囲内に収める必要があります。したがって、以下のポインターを呼び出し側の実行可能ファイルとやり取りすることはできません。
MFC オブジェクトへのポインター
MFC によって割り当てられたメモリへのポインター
呼び出し側の実行可能ファイルと DLL との間で上のポインターや MFC 派生オブジェクトをやり取りする場合は、拡張 DLL を作成する必要があります。
アプリケーションと DLL の間で、C ランタイム ライブラリによって割り当てられたメモリへのポインターをやり取りする場合は、そのデータのコピーを作成しておくと安全です。これらのポインターを削除したり、サイズを変更しないでください。また、これらのポインターを使用する場合は、メモリのコピーを必ず作成してください。
MFC と動的にリンクされるレギュラー DLL をビルドする場合は、AFX_MANAGE_STATE マクロを使って、MFC のモジュール状態を正しく切り替える必要があります。これは、DLL からエクスポートされる関数の先頭に次のコード行を追加して行います。
AFX_MANAGE_STATE(AfxGetStaticModuleState( ))
AFX_MANAGE_STATE マクロは、MFC と静的にリンクされるレギュラー DLL の中では使用しないでください。詳細については、「MFC モジュールの状態データの管理」を参照してください。
レギュラー DLL の記述、ビルド、使用方法の例については、サンプルの DLLScreenCap を参照してください。MFC と動的にリンクするレギュラー DLL の詳細については、サンプル要約の「DLLScreenCap を変換して MFC DLL に動的にリンクする方法」を参照してください。