TN033: MFC の DLL バージョン

このノートでは、MFCxx.DLL を使用することができますおよび MFCxxD.DLL (x は MFC のバージョン番号です) ダイナミック リンク ライブラリの MFC アプリケーションや拡張 Dll と共有方法について説明します。レギュラー Dll の詳細についてを使用して MFC DLL の一部として参照してください。

このテクニカル ノートでは、Dll の 3 つの側面について説明します。最後の 2 つのより高度なユーザーです。:

(これは、レギュラー DLL と呼ばれます) の非 MFC アプリケーションで使用できる MFC を使用して、DLL の構築に興味を持っている場合は、テクニカル ノート 11を参照してください。

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

レギュラー DLL: レギュラー DLL を使用していくつかの MFC クラスを使用して、スタンドアロンの DLL を作成します。アプリケーションと DLL の境界を越えてインターフェイス"C"インターフェイスをクライアント アプリケーションを MFC アプリケーションにする必要はありません。

これは MFC 1.0 でサポート DLL サポートのバージョンです。テクニカル ノート 11と Mfc サンプルの説明 DLLTRACE

特価;Visual C のバージョン 4.0、 USRDLLという用語は使用されていません、静的に MFC にリンクされるレギュラー DLL に置き換えされています。動的に MFC にリンクされるレギュラー DLL を作成することもことがあります。(&N)。

MFC 3.0 以降定期的な Dll OLE とデータベース クラスを含むすべての新しい機能をサポート。

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

特価;バージョン 4.0 の Visual C のこの DLL の種類は「拡張として DLL。「呼ばれます(&N)

このノートを含む MFC DLL を設定、全体を参照してくださいに MFCxx.DLL を使用します。:

特価;[MFCSxx [U] [D]。LIB ライブラリの使用、MFC の共有 Dll。これらのライブラリが含まれているコードは、アプリケーションまたは DLL に静的にリンクする必要があります。(&N)。

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

「MFC 拡張 DLL」MFCxx.DLL にビルドされた DLL です (または他の MFC Dll が共有します)。ここでは、MFC コンポーネント アーキテクチャ キックします。便利なクラスは、MFC クラスから派生した場合に、別の MFC に似たツールキットをビルドするか、DLL に配置できます。究極のクライアント アプリケーションが DLL MFCxx.DLL、使用すること。これは、再利用可能な葉クラス、再利用可能な基本クラス、および再利用可能なビューやドキュメントのクラスを許可します。

特価;アプリケーション、MFC および OLE、データベース、またはネットワークのクラスをそれぞれ使用していない限り、MFCOxx [U] D、MFCDxx [U] D または D MFCNxx [U] をデバッグ ライブラリとリンクする必要はありません。(&N)。

長所と短所

MFC の共有バージョンを使用する理由?

なぜ、共有バージョンの MFC を使用しないでください。:

MFC 拡張 DLL を作成する方法

MFC 拡張 DLL は、クラスと MFC クラスの機能を飾るに書かれた関数を含む DLL です。OLE とデータベースのデバッグ サポート Dll (MFCOxxD.DLL、MFCDxxD.DLL) MFCxxD.DLL を使用は、MFC 拡張 Dll の例です。アプリケーションは、いくつかの追加の考慮事項を使用して、同じ方法で、共有 MFC Dll を MFC 拡張 DLL を使用します。:

これらの考慮事項は、以下で詳しく説明します。あなたも、MFC の高度な概念のサンプルを参照してください それを示していますのでDLLHUSK

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

特価;C++ の名前の変更とエクスポート問題のため、拡張 DLL のエクスポート リストは別のプラットフォームをデバッグ バージョンとリテール バージョン、同じ DLL のと Dll の間異なる場合があります。小売 MFCxx.DLL 約 2000年のエントリ ポイントをエクスポートしている;デバッグ MFCxxD.DLL 約 3000 のエントリ ポイントをエクスポートしています(&N)。

メモリ管理の速いメモ

このテクニカル ノートの終わり近くの「メモリ管理」のセクションでは、MFCxx.DLL の実装は MFC の共有バージョンをについて説明します。ここでは、拡張 DLL の実装に必要な情報が記載されています。

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

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

同様にから、リソースをロードするには、現在の実行可能ファイルのような他「グローバル」の MFC 状態をも、クライアント アプリケーションとすべての MFC 拡張 Dll との間 MFCxx.DLL 自体を共有されます。

拡張 DLL をビルド

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

MFC 拡張 DLL は、既存のプロジェクトを変換する場合は、共有バージョンの MFC を使用するアプリケーションを構築するため、標準的なルールを開始し、次の操作を行います:

ヘッダー ファイルの変更

拡張機能の目標は、DLL はその機能を使用することができます 1 つまたは複数のアプリケーションに共通の機能をエクスポートするのには通常です。これは、クラスと、クライアント アプリケーションで使用できるグローバル関数をエクスポートするに集約します。

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

あなたの全体のクラスをエクスポートするには、 AFX_EXT_CLASSをクラス定義に使用します。このマクロは_AFXDLL_AFXEXT定義しますが、用意されて_AFXEXTが定義されていない状態を定義するとき、フレームワークによって__declspec(dllexport)として定義されています。_AFXEXT上記としてのみ、拡張 DLL をビルドすると定義されます。たとえば:

aFX_EXT_CLASS CExampleExport クラス: パブリック CObject{... クラス定義.}

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

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

たとえば:

 cExampleDialog クラス: パブリック CDialog{パブリック。特価;AFX_EXT_CLASS CExampleDialog();AFX_EXT_CLASS int DoModal();・ ・残りのクラス定義...}(&N)

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

たとえば、 DECLARE_DYNAMICマクロとして次のように、拡張 DLL をビルドするとき定義します。:

# define DECLARE_DYNAMIC(class_name) \保護: \特価;静的 CRuntimeClass ※ パスカル _GetBaseClass();\パブリック: \静的 AFX_DATA CRuntimeClass クラス ## class_name;\仮想 CRuntimeClass ※ const GetRuntimeClass();\(&N)

「静的AFX_DATA」で始まる行は、静的な内部クラス オブジェクトを宣言されていますいます。このクラスを正しくエクスポートし、クライアントからのランタイム情報にアクセスするには。EXE、このスタティック オブジェクトをエクスポートする必要があります。静的オブジェクトは修飾子AFX_DATAで宣言されているため、あなただけ__declspec(dllexport) DLL のビルド時にAFX_DATAを定義し、それとして用意されてクライアントの実行可能ファイルを作成するとき定義する必要があります。

上記で説明したように、この方法ではAFX_EXT_CLASSが既に定義されています。だからあなただけAFX_EXT_CLASSと同じクラス定義を回避するには、 AFX_DATAを再定義する必要があります。

たとえば:

特価;#undef AFX_DATA#define AFX_DATA AFX_EXT_CLASSCExampleView クラス: パブリック CView{DECLARE_DYNAMIC()//... クラス定義.};#undef AFX_DATA#define AFX_DATA(&N)

MFC では、常に、この手法などのすべてのシナリオで動作しますのでそれ、マクロ内で定義するデータ項目のAFX_DATAシンボルが使用されます。たとえば、 DECLARE_MESSAGE_MAPの機能します。

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

自動的にCArchive抽出演算子DECLARE_SERIALIMPLEMENT_SERIALマクロを使用してクラスをエクスポートするのにには、同じ手法を使用できます。クラス宣言を括弧で演算子をエクスポート (には。H ファイル) を次のコード:

#undef AFX_API# define AFX_API AFX_EXT_CLASSlt; あなたのクラス宣言をここで >#undef AFX_API# define AFX_API

_AFXEXT の制限

拡張 Dll の複数の層があるない限り、あなたの拡張機能 Dll の _AFXEXTのプリプロセッサ シンボルを使用できます。拡張 Dll を呼び出す、または独自の拡張 Dll は、MFC クラスから派生し、クラスから派生があいまいさを避けるために独自のプリプロセッサ シンボルを使用する必要があります。

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

複数のレイヤーがある場合は、拡張 DLL がありますが新しいクラスのエクスポートし同様以来別の拡張 DLL から他のクラスをインポート、 AFX_EXT_CLASSなどの 1 つの記号は不十分、です。この問題に対処するには、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)# 他# define CLASS_DECL_A 用意されて#endifCLASS_DECL_A CExampleA クラス: パブリック CObject{... クラス定義...};//B.H#ifdef B_IMPL# define CLASS_DECL_B __declspec(dllexport)# 他# define CLASS_DECL_B 用意されて#endifCLASS_DECL_B CExampleB クラス: パブリック CExampleA{... クラス定義..}(&N)

A.DLL をビルド時に、 /D A_IMPLの構築し、B.DLL をビルド時に、 /D B_IMPLとは。別のシンボルでは、各 DLL を使用して、CExampleB がエクスポートされ、CExampleA B.DLL をビルド時にインポートされます。CExampleA は A.DLL をビルドするときをエクスポートし、B.DLL (またはいくつかの他のクライアント) を使用するとインポート。

このレイヤーの種類、組み込みのAFX_EXT_CLASSおよび_AFXEXTのプリプロセッサ シンボルを使用する場合は実行できません。この解決方法でとは違って、OLE、データベース、およびネットワークの拡張 Dll を構築する場合 MFC 自体のメカニズムを使用上記技術。

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

また、クラス全体をエクスポートしない場合注意する必要があります。MFC マクロによって作成された必須のデータ アイテムが正しくエクスポートされることを確認する必要があります。これは、特定のクラスのマクロにAFX_DATAを再定義して行うことができます。これは、クラス全体をエクスポートしないいつでも行う必要があります。

たとえば:

//A.H#ifdef A_IMPL特価;# define CLASS_DECL_A _declspec(dllexport)# 他# define CLASS_DECL_A _declspec(dllimport)#endif#undef AFX_DATA#define AFX_DATA CLASS_DECL_ACExampleA クラス: パブリック CObject{DECLARE_DYNAMIC()CLASS_DECL_A int SomeFunction();//class の定義。..};#undef AFX_DATA#define AFX_DATA(&N)

DllMain

メイン ソース ファイルに拡張 DLL を配置する必要があります正確なコードを次に示します。後に、標準が含まれています、来てください。AppWizard を使用してスターター ファイル拡張 DLL を作成するときは、 DllMainを供給注。

#include"afxdllx.h"静的な AFX_EXTENSION_MODULE extensionDLL;extern"C"int APIENTRY DllMain (HINSTANCE hInstance, DWORD dwReason、LPVOID){特価;場合 (dwReason DLL_PROCESS_ATTACH = =){//拡張機能 DLL の one-time initialization if (!AfxInitExtensionModule (extensionDLL、hInstance))0 を返します。//TODO: ここに他の初期化タスクを実行}他の場合 (dwReason DLL_PROCESS_DETACH = =){//拡張 DLL プロセス終了AfxTermExtensionModule(extensionDLL);//TODO: ここにその他のクリーンアップ タスクを実行}1 を返す;//ok}(&N)

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

アプリケーションが読み込まれ、拡張 Dll を動的に解放する場合、 AfxTermExtensionModuleとして示すように above.nbsp をコールすることを確認する;またAfxLoadLibraryAfxFreeLibraryアプリケーションが複数のスレッドを使用している場合 (Win32 関数の代わりにLoadLibraryFreeLibrary) を使用する必要があります。AfxLoadLibraryAfxFreeLibraryを使用して、拡張 DLL の読み込みおよびアンロードするときに実行されるスタートアップとシャット ダウンのコードのグローバルな MFC の状態が壊れていないことを保証します。(&N)。

AFXDLLX のヘッダー ファイル。H が含まれている特別なインクルードファイル拡張 Dll、 AFX_EXTENSION_MODULECDynLinkLibrary定義などの構造を。

ExtensionDLLの世界のように宣言する必要があります。16 ビット バージョンの MFC とは異なり、メモリの割り当てし、MFCxx.DLL は、 DllMainが呼び出された時点で完全に初期化されるのでこの時間中には、MFC 機能を呼び出すことができます。

リソースやクラスの共有

単純な MFC 拡張 Dll のみいくつか低帯域幅クライアント アプリケーションは何もに詳細エクスポート機能必要があります。複数ユーザー インターフェイス集中 Dll リソースや C++ クラスをクライアント アプリケーションにエクスポートする必要があります。

リソースをエクスポートするリソース リストを通して行われます。各アプリケーションには、 CDynLinkLibraryオブジェクトのシングル リンク リストです。負荷のリソースが、現在リソース モジュール (AfxGetResourceHandle) 最初見ること、標準の mfc のほとんどのリソースを探していると見つかりません歩く場合は、要求されたリソースの読み込みを試みるCDynLinkLibraryオブジェクトのリスト。

C++ オブジェクトの C++ クラス名の動的な作成と似ています。MFC オブジェクトの逆シリアル化機構は以前格納されたものに基づいて、必要な型の C++ オブジェクトを動的に作成することによって再構築することができますように登録CRuntimeClassオブジェクトのすべてが必要。

Declare_serialクラスで、拡張 DLL を使用するクライアント アプリケーションをする場合は、クライアント アプリケーションに表示されるように、クラスをエクスポートする必要があります。また、 CDynLinkLibraryリストを徒歩でこれです。

Mfc サンプルの場合 DLLHUSKリストのような何かを見える

ヘッド - gt;DLLHUSK。EXE または DLLHUSK です。EXE||TESTDLL2。DLL TESTDLL2。DLL||TESTDLL1。DLL TESTDLL1。DLL||MFCO42D。DLL??????????????? |||MFCD42D。DLL??????????????? |||MFC42D。DLL MFC42。DLL(&G)

MFCxx.DLL は、通常、リソースやクラスのリストに最後です。MFCxx.DLL にはプロンプトの文字列をすべて、標準コマンド Id を含む、標準の MFC リソースのすべてが含まれています。Dll と持っていないことをクライアント アプリケーション自体はリストの末尾に配置することができますは、MFCxx.DLL 内の共有リソースの代わりに依存するが、標準の MFC リソースの独自のコピー。

すべての Dll のクラス名とリソースは、クライアント アプリケーションの名前空間にマージ Id を注意する必要がある欠点や名前を選択しています。リソースまたはCDynLinkLibraryオブジェクトをクライアント アプリケーションにエクスポートしない場合で、この機能を無効にすること当然することができます。 DLLHUSKサンプルは複数のヘッダー ファイルを使用して、共有リソースの名前空間を管理します。テクニカル ノート 35共有リソース ファイルを使用するためのヒントを参照してください。

DLL の初期化

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

このアプローチを使用する場合は、DLL を使う各クライアント アプリケーションこの初期化ルーチンを呼び出す必要があります。ちょうどAfxInitExtensionModuleを呼び出した後、このCDynLinkLibraryオブジェクトをDllMainで割り当てることがあります。

初期化ルーチンCDynLinkLibraryオブジェクトを拡張 DLL 情報をワイヤード (有線)、現在のアプリケーションのヒープに作成する必要があります。これは、次のように行うことができます。:

extern"C"extern 無効 WINAPI InitXxxDLL(){特価;新しい CDynLinkLibrary(extensionDLL);}(&N)

ルーチンの名前は、 InitXxxDLLこの例では、あなたが望むものをすることができます。それする必要はありません extern “C” 、ので、エクスポート リストの保守が簡単になりますが、。

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

エントリをエクスポートします。

クラスをエクスポートして、簡単な方法は用意されて__declspec(dllexport)各クラスとグローバル関数をエクスポートするを使用することです。これは簡単しますが、関数はエクスポートより少ない制御して序数で関数をエクスポートすることはできませんので (後述) の各エントリ ポイントの名前よりも効率が悪くなります。これは TESTDLL1 と TESTDLL2 の両方を使用してそのエントリをエクスポートする方法です。

効率的な方法 (MFCxx.DLL を使用する方法) の各エントリに名前を付けて各エントリを手動でエクスポートするあり。DEF ファイル。私たちの DLL (つまり、すべて) からの選択の輸出をエクスポートするため、我々 はエクスポートする、特定のインターフェイスを決める必要があります。破損した名前をリンカーにエントリの形式で指定する必要がありますので、これは難しいです。DEF ファイル。本当のそれのためのシンボリック リンクを必要としない限り、C++ のクラスをエクスポートしないでください。

しようとしている C++ のエクスポート クラスの場合とします。DEF ファイル、このリストを自動的に生成するツールを開発することがあります前に。これを行うことができます 2 段階のリンクを使用します。かつてない輸出と DLL をリンクし、生成するリンカーを許可します。マップ ファイルです。。マップ ファイルを使用して、いくつかのマンジングとは、それ用の EXPORT エントリを生成するために使用できるように、エクスポートする関数の一覧を生成することができますあなた。DEF ファイル。(それは完全に自動ではないといくつかの手を一度中にチューニングが必要ですが) エクスポート リスト MFCxx.DLL および OLE データベース拡張 Dll、数千のようなプロセスで生成されました。

CWinApp 対 CDynLinkLibrary

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

MFC 拡張 DLL を各アプリケーションの余分なデータを維持するために必要がある場合は、 CDynLinkLibraryから新しいクラスを派生して、InitXxxDLL ルーチンを記述する上で作成します。実行すると、DLL は特定の拡張 DLL の 1 つを見つけるにCDynLinkLibraryオブジェクトの現在のアプリケーションの一覧を確認できます。

DLL 実装でリソースを使用します。

前述のとおり、既定リソース負荷最初 EXE または、要求されたリソースが DLL のCDynLinkLibraryオブジェクトの一覧を説明します。すべての MFC Api だけでなく、内部のすべてのコードが、存在する可能性がありますに関係なく、任意のリソースを見つけるためにリソース リストを歩いてAfxFindResourceHandleを使用します。

のみ、特定の場所からリソースをロードする場合は、Api を使用してAfxGetResourceHandleAfxSetResourceHandle古いハンドルを保存し、新しいハンドルを設定します。クライアント アプリケーションに戻る前に、元のリソース ハンドルを復元してください。サンプル TESTDLL2 メニューを明示的にロードすることはこのアプローチを使用してください。

リストは多少遅くなります、リソース ID 範囲の管理が必要ですは、欠点があります。それはいくつかの拡張 Dll にリンクするクライアント アプリケーション、DLL のインスタンス ハンドルを指定しなくても、DLL のリソースを使用できます、利点があります。AfxFindResourceHandleリソース リストを歩くは特定の一致の検索に使用する API です。リソースの種類と名前を受け取り、最初に一致したリソース ハンドル (または NULL) を返します。

DLL バージョンを使用するアプリケーションを書く

アプリケーションの要件

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

開発環境を構築

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

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

  1. [ビルド] メニューから設定を選択します。[プロジェクト設定の一般ページでは、Microsoft Foundation Classes を使用 MFC 共有 dll (MFCxx(d).dll) に設定します。

NMAKE の建物

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

必要なコンパイラ フラグ:

・ D_AFXDLL/MD

・ D_AFXDLL

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

/MD

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

他のすべてのコンパイラ フラグ、MFC の既定値 (たとえば、_DEBUG デバッグ用) を実行します。

ライブラリのリンカーのリストを編集します。変更 NAFXCWD。MFCxxD.LIB にし NAFXCW を変更します。LIB に MFCxx.LIB。MFCOxx[U]D.LIB、MFCDxx[U]D.LIB、MFCNxx[U]D.LIB として適切な (MFC および OLE、データベース、またはネットワークのクラスの使用に必要な) 追加します。LIBC を交換してください。MSVCRT を LIB します。LIB。他の MFC ライブラリと、MFCxxD.LIB が前に配置されていることが重要ですすべての C ランタイム ライブラリ。

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

これらの変更を加えた後、完全な再構築が必要です。

サンプルのビルド

や、共有の NMAKE と互換性のあるメイクファイル、コマンドラインから Visual C からのほとんどの MFC サンプル プログラムを構築することができます。

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

Mfc サンプル DLLHUSK MFC の DLL バージョンで組み込まれています。このサンプルだけでなく MFCxx.DLL には、リンクされたアプリケーションをビルドする方法を示していますが、それも、MFC DLL パッケージ オプションこのテクニカル ノートで後で説明されている MFC 拡張 Dll などの他の機能を示しています。

包装ノート

製品版の Dll (MFCxx [U]。DLL) 再配布は自由です。Dll のデバッグ バージョンが自由に再頒布可能であり、アプリケーションの開発時にのみ使用する必要があります。

デバッグ Dll デバッグ情報を提供します。Visual C デバッガーを使用して、DLL と同様に、アプリケーションの実行をトレースできます。リリース Dll (MFCxx [U]。DLL) のデバッグ情報が含まれていません。

カスタマイズした場合に、Dll を再構築するか、[、それら何か「MFCxx」、MFC SRC ファイル以外 MFCDLL 呼び出す必要があります。MAK は、ビルド オプションについて説明し、DLL の名前を変更するためのロジックが含まれています。このルールは、MFC および OLE、データベース、およびネットワーク MFCOLE で構築された Dll にも適用されます。MAK、MFCDB。MAK と MFCNET。MAK、それぞれ。これらの 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 のほとんどの作業は

16 ビット バージョンの MFC アプリケーションあたりデータいくつか 80 x 86 アセンブリ コード、プロセスごとの例外コンテキスト、およびその他の技術を作成特別なセグメント、スタック セグメントを含む特別なテクニックの数が必要。Win32 するほとんどの時間は、DLL では、プロセスごとのデータが直接サポートします。ほとんどの部分について MFCxx.DLL は NAFXCW です。LIB、DLL にパッケージ化します。MFC ソース コードを見るには、する必要は非常にいくつかの特殊なケースがあるので、非常にほとんどの #ifdef _AFXDLL、見つけません。具体的に Win32 Windows 3.1 (win32 として呼ばれます) に対処するため、特別なケース。MFC DLL はスレッド ローカル ストレージ (TLS) プロセス ローカルなデータを取得するには、Win32 Api を使用する必要がありますので直接 win32 プロセスごとの DLL データをサポートしません。

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

_AFXDLLバージョン通常の MFC クラス ライブラリ ソースとヘッダーの影響は比較的軽微であります。ある特別なバージョンのファイル (AFXV_DLL。追加のヘッダー ファイル (AFXDLL_ H) と同様。H)、メインの AFXWIN が含まれています。H ヘッダー。AFXDLL_。H ヘッダーには、 CDynLinkLibraryクラスとその他の実装の詳細の_AFXDLLアプリケーションや MFC 拡張 Dll の両方が含まれています。AFXDLLX。H ヘッダーの MFC 拡張 Dll (上記参照の詳細) を構築するため提供されています。

正規のソース、MFC ライブラリ MFC SRC にいくつか追加の条件付きコード_AFXDLL #ifdef であります。追加のソース ファイル (DLLINIT。CPP) 追加の DLL の初期化コードとその他の接着剤の MFC の共有バージョンが含まれています。

MFC の共有バージョンをビルドするには、追加ファイルを提供します。(以下、DLL をビルドする方法の詳細を参照)。

MFC DLL のビルド

MFC DLL は意図的に難しい、だからあなたと思う 2 回の再構築 (3 回) それを行う前に。包装問題と以下に示す再配布制限は本当に理解する場合は、MFC DLL を再構築する必要があります、することができます。

MFCDLL。MAK ファイルではデバッグ DLL CodeView 情報を構築します。:

NMAKE/f mfcdll.mak DEBUG = 1 LIBNAME MYMFC =

MFCDLL。MAK ファイルなし CodeView 情報リリース DLL をビルドします。:

NMAKE/f mfcdll.mak デバッグ = 0 LIBNAME MYMFC =

(同様に、MFCOLE を使用しています。MAK、MFCDB。MAK と MFCNET。MAK MFCOxxD.DLL、MFCDxxD.DLL、および MFCNxxD.DLL - MFC および OLE、データベース、およびネットワークのクラスを含む Dll をビルドする)

これは、MFC DLL を MFC SRC ディレクトリと標準の MFCxx.DLL および MFCxxD.DLL 名前のプライベート バージョンをビルドします。新しい Dll を使用するあなたのパスに適切な場所にコピーする必要があります。MFCDLL。MAK メイクファイルもインポート ライブラリ (MFCxx.LIB と MFCxxD.LIB) を再構築し、標準の MFC の LIB ディレクトリに置いています。これは、ため、作成済みの MFCxx.LIB と MFCxxD.LIB であるライブラリに置き換えられます注意してください。

MFC DLL ライブラリの修正版を再配布する場合は、dll、MFCDLL の名前を変更することを確認してください。MAK のメイクファイルと 2 つ。DEF ファイル。「メイクファイル」MFCDLL を参照してください。MAK の詳細情報。

ライブラリを変更して、製品版を再配布することがあります (/リリース) だけは名前を MFCxx.DLL 以外に変更する場合、変更されたライブラリの。デバッグ バージョンのいずれかの組み込みまたはカスタムのビルド デバッグ DLL いない頒布します。

これらの再配布の制限は、主に非標準の拡散を避けるためには可能性のあるウイルスを含む Dll。 理想的には、Dll を再構築する必要はなく、Visual C の製品で提供される組み込みの MFCxx.DLL でアプリケーションを再配布する場合は、自分自身とあなたのユーザーのための多くの問題が回避されます。

メモリ管理

MFCxx.DLL を使用するアプリケーションは、MSVCRTxx.DLL、共有の C ランタイム DLL によって提供される共通のメモリ アロケーターを使用します。両方、アプリケーション、任意の拡張 Dll と MFC Dll 自体は、この共有メモリ アロケーターを使用します。使用して、共有 DLL がメモリの割り当て、MFC Dll は、アプリケーションまたはその逆で後で解放されるメモリを割り当てることができます。アプリケーションと DLL の両方が同じアロケーターを使用する必要がありますので、C++ グローバル演算子新しいまたは演算子を削除をオーバーライドする必要があります。C ランタイムのメモリ割り当てルーチン (malloc など、realloc、無料など。) の残りの部分に同じルールを適用します。

序数 (とクラス dllexport) や DLL に名前を付ける

我々 は使用していない、 class 、C++ コンパイラの__declspec(dllexport)機能。代わりに、輸出のリストはクラス ライブラリのソース (MFCxx.DEF および MFCxxD.DEF) が含まれています。これら選択のエントリ ポイント (関数とデータ) のセットのみをエクスポートします。MFC のプライベート実装の関数やクラスなどの他の記号はエクスポートされませんすべてのエクスポート序数居住者又は非居住者の名前テーブル文字列名前なしで行われます 。

使用して class __declspec(dllexport)小さな Dll を構築するための実行可能な代替することがありますが、大規模な DLL の場合 MFC のように、既定の機構をエクスポート効率や能力の制限 。

このすべての意味は何我々 大量のリリースでは、多くの実行を損なうことや読み込み速度の約 800 キロバイトは MFCxx.DLL の機能をパッケージすることができます。MFCxx.DLL されている 100 K より大きいいたこの方法されていない使用します。これも追加のエントリ ポイントの終わりに追加することにより。DEF ファイル序数によるエクスポートの速度とサイズの効率性を損なうことなくが、簡単なバージョン管理を許可します。MFC クラス ライブラリのメジャー バージョンのリビジョンは、ライブラリの名前を変更されます。つまり、MFC30。DLL は、MFC クラス ライブラリのバージョン 3.0 を含む再頒布可能 DLL です。この DLL のアップグレードと言う仮説の MFC 3.1 では、DLL は MFC31 という名前になります。DLL ではなく。MFC DLL のカスタム バージョンを作成するには、MFC ソース コードを変更する場合は、再度、別の名前 (とできれば「MFC」なし) で名前してください。

番号順テクニカル ノート|nbsp;カテゴリ別テクニカル ノート(&N)

Index