次の方法で共有


テクニカル ノート 33: MFC の DLL バージョン

ここでは、MFC のアプリケーションと拡張 DLL の MFCxx.DLL と MFCxxD.DLL (x は MFC のバージョン番号) 共有ダイナミック リンク ライブラリを使用する方法について説明します。 レギュラー DLL の詳細については、「DLL の構成要素としての MFC を使用する」を参照してください。

このテクニカル ノートは DLL の 3 種類の側面について説明します。 最後の 2 つはより多くの上級ユーザー向けです:

  • MFC 拡張 DLL をビルドします。

  • DLL バージョンの MFC を使用する MFC アプリケーションのビルド方法

  • MFC 共有ダイナミック リンク ライブラリがどのように実装されるか

ビルドを確認する場合は非 MFC アプリケーション (このレギュラー DLL で使用できるとも呼ばれる) を使用して MFC DLL が テクニカル ノート 11"を参照してください。

MFCxx.DLL サポートの概要: 用語とファイル

標準 DLL: MFC クラスのいくつかの方法を使用して、スタンドアロンの DLL のビルドにレギュラー DLL を使用します。 App/DLL の境界を越えてインターフェイスは「C」インターフェイスであり、クライアント アプリケーションは、MFC アプリケーションである必要はありません。

ここでは、MFC 1.0 でサポートされるサポート DLL のバージョンです。 これは テクニカル ノート 11 に記述され、MFC の高度な概念は DLLScreenCapを制御します。

注意

Visual C++ 4.0 以降では、USRDLL 用語は、MFC にレギュラー DLL で廃止され、静的にリンクされるされました。また、MFC と動的にリンクするレギュラー DLL をビルドできます。

MFC 3.0 (以上) に OLE とデータベース クラスを含むすべての新機能のレギュラー DLL をサポートします。

AFXDLL: これは、共有バージョンの MFC ライブラリと呼ばれます。 ここでは、MFC 2.0 で追加された新しいサポート DLL です。 MFC ライブラリ自体は多くの DLL であり、(以下で説明) クライアント アプリケーションや DLL が動的に必要な DLL をリンクします。 application/DLL の境界を越えてインターフェイスは C++/MFC クラス インターフェイスです。 クライアント アプリケーションは、MFC アプリケーションである必要があります。 これはすべての MFC 3.0 Features (例外をサポートする: UNICODE とデータベース クラスではサポートされません。

注意

Visual C++ 4.0 以降では、この種の DLL は「拡張 DLL」と呼ばれます。

ここでは、次の要素を含むすべての MFC DLL 設定に MFCxx.DLL を使用します:

  • デバッグ: MFCxxD.DLL (結合されます)、MFCSxxD.LIB (static)。

  • リリース: MFCxx.DLL (結合されます)、MFCSxx.LIB (static)。

  • Unicode デバッグ: MFCxxUD.DLL (結合されます)、MFCSxxD.LIB (static)。

  • Unicode リリース: MFCxxU.DLL (結合されます)、MFCSxxU.LIB (static)。

注意

MFCSxx U [] [] D .LIB ライブラリは、MFC 共有 DLL とともに使用されます。これらのライブラリは、アプリケーションまたは DLL に静的にリンクするコードが含まれています。

対応するインポート ライブラリとリンク:アプリケーション

  • デバッグ: MFCxxD.LIB

  • リリース: MFCxx.LIB

  • Unicode デバッグ: MFCxxUD.LIB

  • Unicode リリース: MFCxxU.LIB

「MFC 拡張 DLL」は MFCxx.DLL です (やそのほかの MFC の共有 DLL) にビルドされた DLL。 次に、MFC コンポーネントのアーキテクチャがアクティブになります。 MFC クラスから有用なクラスを派生するか、別の MFC のような Toolkit をビルドする場合は、DLL に配置することもできます。 DLL は MFCxx.DLL は、使用する最終的なクライアント アプリケーションです。 これは、再利用可能なリーフ クラス、再利用可能な基本クラスと再利用可能なビュー、ドキュメント クラスを有効にします。

利点と欠点

理由は、MFC の共有バージョンを使用する必要があるか。

  • ライブラリ共有を使用して小さなアプリケーション (MFC ライブラリの使用が最もサイズ未満である最小限にアプリケーションができます。

  • MFC の共有バージョンは、MFC 拡張 DLL とレギュラー DLL をサポートします。

  • 共有 MFC ライブラリを使用するアプリケーションをビルドすると、MFC 自体をリンクする必要がないため、静的にリンクされる MFC アプリケーションをビルドするより高速です。 これは、リンカーがデバッグ情報を圧縮する必要がある DEBUG ビルドで確認できます (デバッグ情報を既に含む DLL とリンクして…アプリケーション内に圧縮されるデバッグ情報が少なくなります。

MFC の共有バージョンを使用する必要がある場合:

  • 共有ライブラリを使用するアプリケーションを提供すると、プログラムの MFCxx.DLL (そのほか) ライブラリを提供する必要があります。 MFCxx.DLL は多くのように自由に再頒布可能 DLL ですが、セットアップ プログラムで DLL をインストールする必要があります。 さらに、そのプログラムと MFC DLL の両方で使用される C ランタイム ライブラリを含む MSVCRTxx.DLL を用意する必要があります。

MFC 拡張 DLL を作成する方法

MFC 拡張 DLL は、MFC クラスの機能を拡張するために作成された DLL の包含クラスと関数です。 MFC 拡張 DLL は、MFC DLL をアプリケーションでいくつかの追加の考慮事項が設定、同じように使用する:

  • ビルド処理には数個の共有 MFC ライブラリをほかのコンパイラ オプションとリンカー オプションを使用するアプリケーションの作成に似ています。

  • MFC 拡張 DLL は、CWinApp-派生クラスにはありません。

  • MFC 拡張 DLL は、特殊な DllMainを提供する必要があります。 AppWizard に変更できる DllMain 関数が用意されています。

  • MFC 拡張 DLL は、拡張 DLL をアプリケーションに CRuntimeClass[またはリソースをエクスポートするには CDynLinkLibrary を作成するために初期化ルーチンを提供します。 CDynLinkLibrary の派生クラスは、アプリケーション データが拡張 DLL で保持する必要がある場合は、使用される可能性があります。

これらの考慮事項は、後で詳しく説明します。 説明するため、MFC サンプル DLLHUSK を参照する必要があります:

  • 共有ライブラリを使用するアプリケーションの作成。(DLLHUSK.EXE は MFC ライブラリ、またはそのほかの DLL と動的にリンクする MFC アプリケーションです)。

  • MFC 拡張 DLL をビルドする。(拡張 DLL のビルドで使用される _AFXEXT などの特別なフラグに注意してください。)

  • MFC の拡張 DLL の 2 例。 1 は、エクスポート (TESTDLL1) およびそのほかの MFC 拡張 DLL の基本的な構造を全体のクラス インターフェイス (TESTDLL2) をエクスポートする方法を示します。

クライアント アプリケーションおよび拡張 DLL は、MFCxx.DLL の同じバージョンを使用する必要があります。 MFC DLL の規則に従って、デバッグを提供し、(拡張 DLL は /release) リテール バージョンをする必要があります。 これはクライアント プログラムがアプリケーションのデバッグ バージョンとリテール バージョンの両方をビルドし、すべての DLL の適切なデバッグまたはリリース バージョンとリンクできるようにします。

注意

C++ の名前の利点として、またエクスポート問題が、拡張 DLL のエクスポート リスト別のプラットフォームで同じ DLL のデバッグ バージョンとリテール バージョンごとに異なる可能性があります。リテール MFCxx.DLL には、約 2000 のエクスポート エントリ ポイントがあります。; デバッグ MFCxxD.DLL には、約 3000 のエクスポート エントリ ポイントがあります。

メモリ管理の簡単な説明

このテクニカル ノートの末尾付近に「メモリ管理」、というセクションで MFC の共有バージョンで MFCxx.DLL の実装について説明します。 、拡張 DLL を実装するために理解しておく必要がある情報を次に示します。

同じアプリケーション内にあるように、クライアント アプリケーションのアドレス空間に読み込まれた MFCxx.DLL とすべての拡張 DLL がメモリ アロケーター、リソースの読み込みやそのほかの MFC 「Global」状態を使用します。 ここでは、MFC と静的にリンクされるレギュラー DLL と非 MFC DLL ライブラリがまったく逆のし、独自のメモリ プールから割り当てた各 DLL があるため重要です。

拡張 DLL がメモリを割り当てた場合、そのメモリは他のアプリケーション割り当てられたオブジェクトも自由に使用できます。 も共有 MFC ライブラリを使用するアプリケーションがクラッシュした場合、オペレーティング システムの保護は、DLL を共有する他の MFC アプリケーションの整合性が保持されます。

同じように、リソースのクライアント アプリケーションとすべての MFC 拡張 DLL、MFCxx.DLL 自体の間で読み込む現在の実行可能ファイルなど、他の「」グローバルな MFC の状態は、共有されます。

拡張 DLL のビルド

MFC の拡張 DLL のプロジェクトを作成するには、AppWizard を使用して自動的に適切なコンパイラとリンカーの設定を生成します。 また、生成して変更できる DllMain 関数が使用されます。

MFC の拡張 DLL は、既存のプロジェクトを変更する場合は、アプリケーションをビルドするための標準規則から MFC の共有バージョンを使用して開始、次をする:

  • コンパイラ フラグに /D_AFXEXT を追加します。 プロジェクトのプロパティ ダイアログの C/C++ ノードを選択します。 その後、プリプロセッサのカテゴリを選択します。 マクロ定義に _AFXEXT をフィールドを選択して追加し、セミコロンの項目のそれぞれが分離されます。

  • /Gy のコンパイラ スイッチを削除します。 プロジェクトのプロパティ ダイアログの C/C++ ノードを選択します。 その後、コード生成カテゴリを選択します。 「Enable Function-Level Linking」オプションが有効になっていることを確認します。 これは、リンカーが未参照のな関数を削除しないため、クラスをエクスポートしやすくなります。 MFC と静的にリンクされるレギュラー DLL をビルドする元のプロジェクトで使用されている **/MD[d]**に /MT[d] のコンパイラ オプションを変更します。

  • リンクするに /DLL オプションのエクスポート ライブラリをビルドします。 これは、新しいターゲットを作成するときに設定され、Win32 ダイナミック リンク ライブラリを対象の型を指定します。

ヘッダー ファイルの変更

拡張 DLL の目的は、その機能を使用して、一つ以上のアプリケーションに共通の機能をエクスポートします。 これにより、クライアント アプリケーションで使用できるグローバル関数、およびグローバル変数のエクスポートに沸きます。

これを行うには、メンバー関数で適切にインポートまたはエクスポートとしてマークされていることを確認する必要があります。 これは、特別な宣言が必要です: __declspec(dllexport)__declspec(dllimport)。 クラスはクライアント アプリケーションで使用される場合、その関数に **__declspec(dllimport)として宣言します。 拡張 DLL 自体が構築されている場合は、__declspec(dllexport)**として宣言する必要があります。 また、クライアント プログラムが読み込み時にバインドするように実際にエクスポートしてください。

クラス全体をエクスポートするには、クラス定義で AFX_EXT_CLASS を使用します。 このマクロは __declspec(dllexport) と、フレームワークによって _AFXEXT が定義されていない場合 _AFXDLL_AFXEXT で定義されているが、定義されて __declspec(dllimport) で定義されます。 既に 説明したように**_AFXEXT** は、拡張 DLL をビルドする場合に定義します。 たとえば、次のようになります。

class AFX_EXT_CLASS CExampleExport : public CObject
{ ... class definition ... };

クラス全体をエクスポートしない場合

クラスでは、個々の必要なメンバーをエクスポートすることもできます。 たとえば、CDialog 派生クラスをエクスポートする場合、エクスポートする必要があるのはコンストラクターと DoModal 呼び出しだけです。 DLL の .DEF ファイルを使用すると、これらのメンバーをエクスポートできますが、エクスポートする必要のある各メンバーに対して AFX_EXT_CLASS とほぼ同じ方法で使用できます。

たとえば、次のようになります。

class CExampleDialog : public CDialog
{
public:
   AFX_EXT_CLASS CExampleDialog();
   AFX_EXT_CLASS int DoModal();
   // rest of class definition
   .
   .
   .
};

これを行うと、そのクラスのすべてのメンバーをエクスポートしていないため、追加の問題に実行できます。 問題は、MFC マクロの動作方法になります。 MFC のいくつかのヘルパー マクロは、実際にデータ メンバーを宣言または定義しています。 したがって、これらのデータ メンバーは、DLL からエクスポートされる必要があります。

たとえば、拡張 DLL をビルドする場合、DECLARE_DYNAMIC マクロは次のように定義されます。

#define DECLARE_DYNAMIC(class_name) \
protected: \
   static CRuntimeClass* PASCAL _GetBaseClass(); \
   public: \
   static AFX_DATA CRuntimeClass class##class_name; \
   virtual CRuntimeClass* GetRuntimeClass() const; \

「静的な AFX_DATA」を開始行は、クラス内部の静的オブジェクトを宣言しています。 このクラスを適切にエクスポートし、クライアント .EXE からランタイム情報にアクセスするには、この静的オブジェクトをエクスポートする必要があります。 この静的オブジェクトは修飾子 AFX_DATA を付けて宣言されているため、DLL をビルドする場合は AFX_DATA__declspec(dllexport) として定義し、クライアント実行可能ファイルをビルドする場合は __declspec(dllimport) として定義するだけで済みます。

上で説明したように、AFX_EXT_CLASS は、次のように定義されます。 クラス定義の周囲に AFX_EXT_CLASS と同じように AFX_DATA を再定義する必要があります。

たとえば、次のようになります。

   #undef  AFX_DATA
   #define AFX_DATA AFX_EXT_CLASS
   class CExampleView : public CView
   {
     DECLARE_DYNAMIC()
     // ... class definition ...
   };
   #undef  AFX_DATA
   #define AFX_DATA

MFC は、マクロ内で定義されているため、この手法では、このようなすべての状況で有効です AFX_DATA データ項目の記号を使用します。 たとえば、DECLARE_MESSAGE_MAPに適用されます。

注意

選択したクラス メンバーではなく、クラス全体をエクスポートする場合、静的データ メンバーは自動的にエクスポートされます。

自動的に DECLARE_SERIALIMPLEMENT_SERIAL マクロを使用してクラスの CArchive のストリーム演算子をエクスポートするのと同じ方法を使用できます。 クラス宣言のエクスポートします (にあるブラケットでアーカイブ演算子を。次のコードの H ファイル) :

#undef AFX_API
#define AFX_API AFX_EXT_CLASS

<your class declarations here>

#undef AFX_API
#define AFX_API

_AFXEXT に関する制限事項

拡張 DLL のレイヤーがない限り拡張 DLL に_AFXEXT のプリプロセッサ シンボルを使用できます。 MFC クラスから派生している独自の拡張 DLL の中のクラスを呼び出したり、このようなクラスから派生している拡張 DLL がある場合は、あいまいさを避けるために必ず独自のプリプロセッサ シンボルを使ってください。

Win32 での問題は、DLL からエクスポートされるデータは __declspec(dllexport) として、DLL からインポートされるデータは __declspec(dllimport) として、それぞれすべて明示的に宣言する必要があることです。 _AFXEXT を定義すると、MFC ヘッダーは AFX_EXT_CLASS が正しく定義されているかどうか確認します。

複数のレイヤーを設定すると、AFX_EXT_CLASS などの 1 種類のシンボルは拡張 DLL は新しいクラスをエクスポートすると、別の拡張 DLL からクラスをインポートすることをことがあるため、十分ではありません。 この問題に対処するには、DLL の使用と、DLL 自体をビルドしていることを示すために、専用のプリプロセッサ シンボルを使用します。 たとえば、2 拡張 DLL、A.DLL、B.DLL とします。 それぞれ A.H エクスポートと B.H が一部のクラス B.DLL は A.DLL からクラスを使用します。 このとき、ヘッダー ファイルは次のようになります。

/* A.H */
#ifdef A_IMPL
   #define CLASS_DECL_A   __declspec(dllexport)
#else
   #define CLASS_DECL_A   __declspec(dllimport)
#endif

class CLASS_DECL_A CExampleA : public CObject
{ ... class definition ... };

/* B.H */
#ifdef B_IMPL
   #define CLASS_DECL_B   __declspec(dllexport)
#else
   #define CLASS_DECL_B   __declspec(dllimport)
#endif

class CLASS_DECL_B CExampleB : public CExampleA
{ ... class definition .. };

A.DLL のビルド時に、/D A_IMPL で作成され、B.DLL のビルド時に、/D B_IMPLでビルドされます。 DLL のシンボルを使用することにより、CExampleB はエクスポートされ、B.DLL をビルドすると、CExampleA はインポートされます。 CExampleA は B.DLL A.DLL をビルド時にエクスポートおよびインポートする (または他のクライアント) で使用される場合。

レイヤーというこの型は _AFXEXT の組み込み AFX_EXT_CLASS とプリプロセッサ シンボルを使用するときにできません。 上記の方法は MFC 自体が使用する機構とは異なり、OLE データベースやネットワーク拡張 DLL をビルドするときにこの問題のない方法で解決します。

クラス全体をエクスポートしない場合

再びクラス全体をエクスポートしない場合は、特別な注意を払う必要があります。 MFC マクロによって作成された必要なデータ項目が正しくエクスポートされることを確認する必要があります。 これは、特定のクラスのマクロに AFX_DATA を再定義することによって行うことができます。 クラス全体をエクスポートしない場合は、必ずこの処理を行う必要があります。

たとえば、次のようになります。

// A.H
#ifdef A_IMPL
   #define CLASS_DECL_A  _declspec(dllexport)
#else
   #define CLASS_DECL_A  _declspec(dllimport)
   #endif

#undef  AFX_DATA
#define AFX_DATA CLASS_DECL_A

class CExampleA : public CObject
{
   DECLARE_DYNAMIC()
   CLASS_DECL_A int SomeFunction();
   //class definition 
   .
   .
   .
};

#undef AFX_DATA
#define AFX_DATA

DllMain

次に、拡張 DLL の主要なソース ファイルに記述する厳密なコードです。 これは、標準の後に含まれている必要があります。 拡張 DLL の初期ファイルの作成に AppWizard を使用するときに、提供するための DllMain を確認します。

#include "afxdllx.h"

static AFX_EXTENSION_MODULE extensionDLL;

extern "C" int APIENTRY 
DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID)
{
   if (dwReason == DLL_PROCESS_ATTACH)
   {
      // Extension DLL one-time initialization 
      if (!AfxInitExtensionModule(
             extensionDLL, hInstance))
         return 0;

      // TODO: perform other initialization tasks here
   }
   else if (dwReason == DLL_PROCESS_DETACH)
   {
      // Extension DLL per-process termination
      AfxTermExtensionModule(extensionDLL);

          // TODO: perform other cleanup tasks here
   }
   return 1;   // ok
}

AfxInitExtensionModule の呼び出しは CDynLinkLibrary オブジェクトが作成されるとモジュールのランタイム クラスCRuntimeClass (構造体)、後で使用するためのファクトリ オブジェクト (COleObjectFactory オブジェクト) をキャプチャします。 AfxTermExtensionModule を (省略可能な) 呼び出しはクリーンアップ (プロセス終了するか、DLL が FreeLibrary の呼び出しの結果として) アンロードされる各プロセスの拡張 DLL からデタッチするときに MFC 拡張 DLL を示します。 ほとんどの拡張 DLL が動的に (通常、インポート ライブラリによってリンクされます) 読み込まれないため、AfxTermExtensionModule への呼び出しは、通常は必要ではありません。

アプリケーションが動的に拡張 DLL を読み込み、放したら、上記のように AfxTermExtensionModule を呼び出すことを確認してください。 また、アプリケーションが複数のスレッドを使用するか、動的に拡張 DLL を読み込んだら AfxLoadLibraryAfxFreeLibrary を使用してください (Win32 関数の LoadLibraryFreeLibraryは機能します)。 AfxLoadLibraryAfxFreeLibrary を使用して拡張 DLL に読み込まれ、アンロードされるグローバルな MFC の状態を破損しない場合に実行されるスタートアップ コードと終了することを保証します。

ヘッダー ファイル AFXDLLX.H は AFX_EXTENSION_MODULECDynLinkLibraryに定義などの拡張 DLL で使用する構造体の特別な定義が含まれます。

グローバルな extensionDLL は 次のように宣言する必要があります。 MFC の 16 ビット バージョンとは異なり、DllMain が呼び出されるまでに MFCxx.DLL が完全に初期化されるため、メモリを割り当て、この間に MFC 関数を呼び出すことができます。

リソースやクラスの共有

単純な MFC の拡張 DLL は、クライアント アプリケーションと Nothing にいくつかの低帯域幅の関数がエクスポートするだけです。 より多くのユーザーを大量に使用する DLL は、クライアント アプリケーションにリソース、C++ クラスをエクスポートすることもできます。

リソースのエクスポートには、リソース リストを使います。 各アプリケーションで CDynLinkLibrary オブジェクトのシングルリンク リストです。 リソースを検索するときに、リソースを読み込む標準の MFC 実装のほとんどは、現在のリソース モジュール (AfxGetResourceHandle) を最初に検索と Not ウォークでは CDynLinkLibrary の一覧、要求されたリソースを読み込むようによう試みるに表示します。

C++.クラス名がある C++ オブジェクトを動的に作成する場合も同じです。 MFC オブジェクトの逆シリアル化機能は、要求された型作成できます。構築以前に保存された内容に動的に C++ オブジェクトをと同じように登録されている CRuntimeClass のすべてのオブジェクトが必要です。

DECLARE_SERIALである拡張 DLL でクラスを使用するクライアント アプリケーションを作成するときは、クライアント アプリケーションから参照できるようにクラスをエクスポートする必要があります。 これは、調査することによって CDynLinkLibrary の一覧です。

MFC の高度な概念の場合は DLLHUSKの一覧に次のようにサンプリングする:

head ->   DLLHUSK.EXE   - or -   DLLHUSK.EXE
               |                      |
          TESTDLL2.DLL           TESTDLL2.DLL
               |                      |
          TESTDLL1.DLL           TESTDLL1.DLL
               |                      |
               |                      |
            MFC90D.DLL            MFC90.DLL

MFCxx.DLL はリソースやクラス リストの最後に原因です。 MFCxx.DLL はすべての標準コマンド ID のプロンプト文字列を含む標準 MFC リソースすべてが含まれます。 これをリストの割り当て DLL と標準 MFC リソースの独自のコピーを持つ、MFCxx.DLL の共有リソースに依存するクライアント アプリケーション自体の末尾に配置されます。

任意の ID または名前を選択するかは、慎重にある場合、クライアント アプリケーションの名前空間へのすべての DLL のリソース名とクラス名をマージに短所があります。 クライアント アプリケーションのリソースまたは CDynLinkLibrary オブジェクトのエクスポートにして、この機能を無効にすることができます。 DLLHUSK サンプルでは、複数のヘッダー ファイルを使って、共有リソースの名前空間を管理します。 共有リソース ファイルの使い方のヒントについては、テクニカル ノート 35 を参照してください。

DLL の初期化

前述のように、通常、クライアント アプリケーションでリソースやクラスをエクスポートするに CDynLinkLibrary オブジェクトを作成する必要があります。 DLL を初期化するためにエクスポートされたエントリ ポイントを提供する必要があります。 少なくとも、これは、引数を受け取らず、が Nothing 返さない、自由になります。void なルーチンです。

DLL を使用する各クライアント アプリケーションはこの方法を使用すると、この初期化ルーチンを呼び出す必要があります。 また AfxInitExtensionModuleを呼び出した直後の DllMainCDynLinkLibrary オブジェクトを割り当てることができます。

初期化ルーチンは拡張 DLL で縛られるまで情報が現在のアプリケーション ヒープで CDynLinkLibrary オブジェクトを作成する必要があります。 これは次のできます:

extern "C" extern void WINAPI InitXxxDLL()
{
   new CDynLinkLibrary(extensionDLL);
}

定期的な名前 (この例で InitXxxDLL は、必要に応じていくつでもかまいません。 これは extern "C"である必要はありませんが、このようにすると、エクスポート リストを管理しやすくなります。

注意

レギュラー DLL から拡張 DLL を使用する場合、この初期化関数をエクスポートする必要があります。この関数は、拡張 DLL のクラスまたはリソースを使用する前に、レギュラー DLL から呼び出す必要があります。

エントリのエクスポート

クラスをエクスポートする簡単な方法は、エクスポートするグローバル関数、各クラスの __declspec(dllimport)__declspec(dllexport) を使用します。 これにより、関数をエクスポートし、序数で関数をエクスポートできないことをあまり制御できるので、簡単にしますが、の各エントリ ポイントというほど効率的 (以下で説明)。 TESTDLL1 と TESTDLL2 はエントリをエクスポートするには、このメソッドを使用します。

効果的な方法 (および MFCxx.DLL で使用されるメソッド) .DEF ファイルの各エントリを指定することにより、各エントリを手動でエクスポートです。 これで、DLL (すべて) から選択的なエクスポートをエクスポートするので、どの点インターフェイスをエクスポートする前にするかを決定する必要があります。 これは、.DEF ファイルのエントリの形式でリンカーに分解された名前を指定する必要があるため、困難です。 実際に、のシンボリック リンクを持つ必要がない C++ クラスをエクスポートしないでください。

ある C++ をエクスポートすると、.DEF ファイルの前に、このリストを自動的に生成するツールを開発できます。分類します。 これは、正常な更新リンク プロセスを使用して実行できます。 DLL をエクスポートせずに一度リンクし、リンカーが .MAP ファイルが生成されるようにします。 .MAP ファイルをエクスポートする必要があるため、再配列と、.DEF ファイルのエクスポート エントリを生成するために使用できる関数のリストを生成するために使用できます。 数千 MFCxx.DLL、OLE、およびデータベースの拡張 DLL のエクスポート リストは数に、このようなプロセスと (完全に自動的にすることも true 手を必要としない) が生成されます。

CWinApp は CDynLinkLibrary

MFC 拡張 DLL は、CWinApp-独自の派生オブジェクトにはありません; 代わりに、CWinApp-クライアント アプリケーションの派生オブジェクトを使用する必要があります。 これはクライアント アプリケーションはメイン メッセージ ポンプを所有していることを、アイドル ループなどを意味します。

MFC 拡張 DLL が各アプリケーション用の追加データを保持する必要がある場合 CDynLinkLibrary から新しいクラスを派生し、それを InitXxxDLL ルーチンで作成する上で記述します。 DLL は、実行時に現在のアプリケーションの CDynLinkLibrary オブジェクト リストから特定の拡張 DLL 用のオブジェクトを探し出します。

DLL の実装の Using Resources

前述のように、既定のリソースの読み込みはリスト要求されたリソースを持つ最初の EXE または DLL を検索 CDynLinkLibrary オブジェクトを調べます。 存在する場合でも、どこでリソースを検索するすべての MFC API、すべての内部コードを使用 AfxFindResourceHandle リソースのリストです。

特定の場所からリソースを読み込み、古いハンドルのみを格納するために使用できる API AfxGetResourceHandleAfxSetResourceHandle を使って新規ハンドルを設定する場合。 クライアント アプリケーションに戻る前に、元のリソース ハンドルを必ず復元してください。 サンプル TESTDLL2 は明示的にメニューを読み込むには、この方法を使用します。

リストを検索する場合、多少速度が低下することとリソース ID 範囲の管理が必要なことが欠点です。 複数の拡張 DLL にリンクされるクライアント アプリケーション側で、DLL のインスタンス ハンドルを指定しなくても、DLL が提供する任意のリソースを使用できるという利点もあります。 AfxFindResourceHandle は、リソース リストを検索して一致するリソースを見つけるのに使われる API です。 リソースの名前と型を受け取り、最初に一致したリソース ハンドル (または NULL) を返します。

DLL を使用するアプリケーションを記述します。

アプリケーションの要件

MFC の共有バージョンを使用するアプリケーションでは、いくつかの簡単な規則に従う必要があります:

  • これは CWinApp オブジェクトが必要で、標準にメッセージの規則はポンプします。

  • 次に、のコンパイラ フラグ (以下を参照) でコンパイルする必要があります。

  • これは、MFCxx のインポート ライブラリとリンクする必要があります。 必須のコンパイラ フラグを設定することにより、MFC ライブラリのヘッダーはアプリケーションをリンクさせるリンク時に決定されます。

  • 実行可能ファイルを実行するには、パスには MFCxx.DLL または Windows のシステム ディレクトリに置く必要があります。

開発環境でビルド

標準の既定のほとんどの内部メイクファイルを使用すると、簡単に DLL バージョンをビルドするプロジェクトを変更できます。

次の手順では、(デバッグ) の NAFXCWD.LIB とリンクされる MFC アプリケーションが正しく機能、ことを想定して NAFXCW.LIB (リテール用) と共有バージョンの MFC ライブラリを使用するように変換する必要があります。 Visual C++ の環境を実行して、内部プロジェクト ファイルがあります。

  1. プロジェクト メニューで、[プロパティ] をクリックします。 プロジェクトの既定値全般 ページで、共有 DLL で MFC を使う (に Microsoft Foundation Class を MFCxx (D) .dll) に設定します。

NMAKE のビルド

Visual C++ の外部メイクファイル機能を使用することも、NMAKE を直接使用している場合は、コンパイラとリンカー オプションをサポートする場合は、メイクファイルを編集する必要があります。

必須のコンパイラ フラグ:

  • /D_AFXDLL /MD
    /D_AFXDLL

標準の MFC ヘッダーはこのシンボルを定義する必要があります:

  • /MD
    アプリケーションでは、C ランタイム ライブラリの DLL バージョンを使用する必要があります。

他のコンパイラ フラグは、MFC の既定 (デバッグの_DEBUG) に従います。

ライブラリのリンカーのリストを編集します。 NAFXCWD.LIB に MFCxxD.LIB を変更し、NAFXCW.LIB に MFCxx.LIB を変更します。 MSVCRT.LIB と LIBC.LIB を置き換えます。 そのほかの MFC ライブラリと同様に MFCxxD.LIB が before されたすべての C ランタイム ライブラリにすることが重要です。

必要に応じて /D_AFXDLL をリリースに追加し、リソース コンパイラ オプション (実際に /Rのリソースをコンパイルする 1) をデバッグします。 これにより、MFC DLL にあるリソースを共有すると、最終的な実行可能ファイルをより小さくなります。

フル リビルドは、これらの変更が行われた後でも必要です。

サンプルのビルド

MFC のサンプル プログラムのほとんどは、Visual C++ またはコマンド ラインから共有 NMAKE 互換メイクファイルでビルドできます。

MFCxx.DLL を使用するようにこれらのサンプル変換するには、Visual C++ に .MAK ファイルを読み込み、プロジェクト オプションを上記のように設定できます。 NMAKE のビルドを使用すると、NMAKE のコマンド ラインで「AFXDLL=1」を指定し、共有 MFC ライブラリを使用するサンプルをビルドします。

MFC サンプル DLLHUSK は DLL バージョンの MFC を使用して作成されます。 このサンプルでは、だけでなく、MFCxx.DLL で結合されたアプリケーションを作成する方法を示していますが、このテクニカル ノートで後述する MFC 拡張 DLL などの MFC DLL パッケージ化オプションの他の機能について説明します。

パッケージ化のメモ

DLL (MFCxx [] U .DLL) のリテール バージョンは自由に再頒布可能です。 DLL のデバッグ バージョンは自由に再頒布可能で、アプリケーションの開発時にだけ使用してください。

デバッグ DLL をデバッグ情報が与えられます。 Visual C++ デバッガーを使用して、アプリケーション、または DLL の実行をトレースできます。 リリース DLL (MFCxx [] U .DLL) のデバッグ情報が含まれません。

またはリビルドする DLL をカスタマイズする場合は、「MFCxx 以外は何かを呼び出す必要があります MFCDLL.MAK」MFC ソース ファイルがビルド オプションについて説明し、DLL の名前を変更するためのロジックが含まれています。 ファイルの名前を変更すると、これらの DLL に多数の MFC アプリケーションに、共有されるため、必要な場合もあります。 MFC DLL のカスタム バージョンを持つとシステムにインストールされる機能を共有 MFC DLL を使用して別の MFC アプリケーションが破損することに置き換えます。

MFC DLL をビルドし直すことはお勧めしません。

MFCxx.DLL がどのように実装されるか

以下のセクションでは、MFC DLL (MFCxx.DLL MFCxxD.DLL) とどのように実装されるかを説明します。 理解して次の詳細も、するのはアプリケーションの MFC DLL を使用するだけの場合は重要ではありません。 次の詳細を理解するために必要な MFC 拡張 DLL を作成する方法ではありませんが、この実装を理解すると、独自の DLL の作成に役立つ場合があります。

実装の概要

MFC DLL は、MFC 拡張 DLL の上記の特殊なケースです。 それに多数のクラスを非常に多くのエクスポートがあります。 いくつかの追加機能があります。これをさらに特別にしますが、通常の拡張 DLL で MFC DLL にする。

Win32 には、ほとんどの作業します。

MFC の 16 ビット バージョンは 80x86 アセンブリ コードによって、プロセスごとの例外コンテキスト作成されたスタック セグメント、特別なセグメントなどの、アプリケーション データを含む複数の特別な手法が必要でした。 Win32 には直接である DLL のプロセスごとのデータがサポートされています。ほとんどの場合、必要なものになります。 ほとんどの場合、MFCxx.DLL は DLL にパッケージ化 NAFXCW.LIB だけです。 MFC のソース・コードを調べると、非常に加える必要があるいくつかの特殊なケースであるため、いくつかの #ifdef _AFXDLL が大幅に検索されます。 そこで、特別なケースは、Windows 3.1 の Win32 の処理 (Win32s とも呼ばれる)。 Win32s はプロセスごとの DLL データを直接サポートされないため、MFC DLL がプロセス ローカル データを取得するには、スレッド ローカル ストレージの (TLS) Win32 API を使用する必要があります。

ライブラリ ソース、ファイルの影響

標準 MFC クラス ライブラリのソース ファイルとヘッダーの _AFXDLL バージョンの影響は、比較的小さなです。 特別なバージョン ファイル (AFXV_DLL.H)、およびそのほかのヘッダー ファイルがあります (AFXDLL_.H) メイン AFXWIN.H のヘッダーに格納されています。 AFXDLL_.H のヘッダーは _AFXDLL のアプリケーションおよび MFC 拡張 DLL の CDynLinkLibrary クラスおよびそのほかの実装の詳細が含まれます。 AFXDLLX.H のヘッダーは、MFC 拡張 DLL をビルドするために使用されます。詳細については、"も参照してください。

MFC ソースの MFC ライブラリへの通常のソースに _AFXDLL の #ifdef で追加条件付きコードがあります。 追加のソース ファイル (DLLINIT.CPP) は、MFC の共有バージョン用の追加の DLL の初期化コードやそのほかの接着機能が含まれています。

MFC の共有バージョンをビルドするには、ファイルが表示されます。(DLL をビルドする方法の詳細については、次を参照してください)。

  • 2 個の .DEF ファイルは、Debug (MFCxxD.DEF) の MFC DLL エントリ ポイントをエクスポートするために使用され、(DLL の MFCxx.DEF) バージョンを解放します。

  • .RC ファイル (MFCDLL.RC) は DLL のすべての標準 MFC リソースと VERSIONINFO のリソースが含まれています。

  • .CLW ファイル (MFCDLL.CLW) はクラス ウィザードを使用して MFC クラスを参照するために使用されます。 メモ: この機能は、MFC の DLL バージョンに固有ではありません。

メモリ管理

MFCxx.DLL を使うアプリケーションを MSVCRTxx.DLL によって提供される共通の共有メモリ アロケーター C ランタイム DLL を使用します。 アプリケーションは、MFC DLL として拡張 DLL と十分は、共有メモリ アロケーターを使用します。 メモリ割り当てには共有 DLL を使用すると、MFC DLL は、後でアプリケーションで逆に解放されたメモリを割り当てることができます。 アプリケーションと DLL の両方が同じアロケーターを使用する必要があるので、C++ のグローバル operator new または operator deleteをオーバーライドする必要があります。 これと同じ規則が、C ランタイムのメモリ割り当てルーチンの他に適用されます (mallocreallocfreeなどの)。

Ordinal やクラスに__declspec (dllexport) と DLL の名前

これは C++ コンパイラの class __declspec(dllexport) の機能は使用しません。 代わりに、エクスポートの一覧はクラス ライブラリのソースに含まれています (MFCxx.DEF と MFCxxD.DEF)。 だけこれらのエントリ ポイントの選択設定 (関数とデータ エクスポートされます。 ほかのシンボルは、MFC のプライベートな実装の関数やクラスなど、または非常駐名前テーブルの文字列名なしで序数で、すべてのエクスポートされるエクスポートされません。

class を使用してビルドの小さな DLL の実行可能な選択肢である MFC などの DLL の場合は、機能をエクスポートする既定で効率や容量の制限があります。

すべての measure が、多くの実行が損なわれるまたは速度を読み込まないでは約 800 KB であるリリース MFCxx.DLL で大量の機能をパッケージ化することで、この処理を。 MFCxx.DLL は大きい KB この手法は使用されません。 これは、ファイルに .DEF の最後に追加エントリ ポイントを追加するように序数によるエクスポートの速度とサイズの効率を損なうことなく、単純なバージョン管理できるようにします。 MFC のクラス ライブラリのメジャー バージョンのリビジョンにより、ライブラリ名を変更します。 つまり、MFC30.DLL は MFC クラス ライブラリのバージョン 3.0 を含む再頒布可能な DLL です。 架空の MFC 3.1 でこの DLL のアップグレードは、DLL MFC31.DLL と代わりという名前です。 再度 MFC DLL のカスタム バージョンを生成するために MFC のソース・コードを変更する場合は、別の名前を使用します (と名前の「MFC」なしの場合、1 列を)。

参照

その他の技術情報

番号順テクニカル ノート

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