共用方式為


TN033: MFC DLL 版本

這個記事將告訴您如何可以使用 MFCxx.DLL 和 MFCxxD.DLL (其中 x 是 MFC 的版本號碼) 的擴充 Dll MFC 應用程式與共用動態連結程式庫。 如需有關標準 dll 裡的詳細資訊,請參閱將 MFC 當成 DLL 的一部分

這份技術提示涵蓋三個層面的 Dll。 最後兩個是為進階電腦使用者:

  • 您要如何建立 MFC 擴充 DLL

  • 您要如何建立使用 MFC 的 DLL 版本的 MFC 應用程式

  • MFC 共用動態連結程式庫的方式來實作

如果您是要建置 DLL 使用 MFC,可用來使用這兩個標準 DLL) 的非 MFC 應用程式,請參閱技術提示 11

MFCxx.DLL 支援的概觀: 術語和檔案

標準 DLL 中,: 您可以使用的標準 DLL 來建立獨立的 DLL 使用 MFC 類別的部分。 跨應用程式或 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 程式庫版本。 這是新的 DLL 支援 MFC 2.0 加入。 MFC 程式庫本身是以多種不同的 Dll (說明如下),用戶端應用程式或 DLL 動態連結所需的 Dll。 跨應用程式或 DLL 界限的介面是 C + + /cli MFC 類別介面。 用戶端應用程式必須是 MFC 應用程式。 這種情況支援 MFC 3.0 的所有功能 (例外狀況: UNICODE 不支援的資料庫類別)。

注意事項注意事項

做為的 Visual C++ 4.0 版,這種類型的 DLL 被指 「 擴充 DLL。"

這個註解將會使用 MFCxx.DLL 來參照的整個程式 MFC DLL 組,其中包括:

  • 偵錯: (合併) 的 MFCxxD.DLL 和 MFCSxxD.LIB (靜態)。

  • 發行版本: MFCxx.DLL (合併) 和 MFCSxx.LIB (靜態)。

  • Unicode 偵錯: (合併) 的 MFCxxUD.DLL 和 MFCSxxD.LIB (靜態)。

  • Unicode 版本: MFCxxU.DLL (合併) 和 MFCSxxU.LIB (靜態)。

注意事項注意事項

MFCSxx [U] [D]。LIB 文件庫用於配合 MFC 的共用 Dll。這些程式庫包含必須以靜態方式連結到應用程式或 DLL 的程式碼。

應用程式會連結至對應的匯入程式庫:

  • 偵錯: MFCxxD.LIB

  • 發行版本: MFCxx.LIB

  • Unicode 偵錯: MFCxxUD.LIB

  • Unicode 版本: MFCxxU.LIB

"MFC 擴充 DLL 」 是建立在 MFCxx.DLL DLL (和/或其他 MFC 的共用 Dll)。 這裡的 MFC 元件架構就會啟動。 如果您從 MFC 類別,衍生一個好用的類別,或建立另一個 MFC 類似的工具組,您可以將它放在 DLL 中。 DLL 會使用 MFCxx.DLL,最終的用戶端應用程式一樣。 這可讓可重複使用的分葉類別、 可重複使用的基底類別,以及可重複使用的檢視/文件類別。

優缺點

為什麼您應該使用 MFC 的共用的版本?

  • 使用共用程式庫可能會導致 (最小的應用程式使用 MFC 程式庫的大部分是少於 10 個 K) 的小型應用程式。

  • 共用的 MFC 版本支援 MFC 擴充 Dll 和標準 dll 裡。

  • 建置的應用程式使用共用的 MFC 程式庫是較快,因為它不是連結至 MFC 本身所需建立一個以靜態方式連結的 MFC 應用程式。 特別是在偵錯組建的連結器必須壓縮偵錯資訊的位置,連結的 DLL 已經包含偵錯資訊,只有較少的偵錯訊息需要壓縮您的應用程式中。

為何您不應該使用 MFC 的共用的版本:

  • 傳送使用共用程式庫的應用程式需要您提供的 MFCxx.DLL (與其他人) 與您的程式庫。 MFCxx.DLL 是自由的 Dll,例如可轉散發,但您仍必須安裝該 DLL 安裝程式。 此外,您必須提供 MSVCRTxx.DLL,其中包含同時由您的程式和 MFC Dll 本身所用的 c 執行階段程式庫。

如何撰寫 MFC 擴充 DLL

MFC 擴充 DLL 是指 DLL 包含類別和函式寫入至 MFC 類別的功能來美化它們。 MFC 擴充 DLL 會使用共用的 MFC Dll,應用程式可使用它,多考慮一下的方式相同:

  • 在建置程序很類似建置的應用程式使用共用的 MFC 程式庫與一些其他的編譯器和連結器選項。

  • MFC 擴充 DLL 並沒有CWinApp-衍生的類別。

  • MFC 擴充 DLL 必須提供特殊的DllMain。 即 AppWizard 提供DllMain ,您可以修改的函式。

  • MFC 擴充 DLL 通常會提供要建立一個初始設定常式 CDynLinkLibrary 如果想要匯出的擴充功能 DLL CRuntimeClasses 或應用程式的資源。 在衍生的類別的 CDynLinkLibrary 需要使用由擴充程式 DLL 必須維護每個應用程式資料。

以下的更詳細地說明這些考量。 您也應該參考 MFC 進階概念範例 DLLHUSK 因為它會說明:

  • 建置使用共用程式庫的應用程式。 (DLLHUSK。EXE 是 MFC 應用程式動態連結至 MFC 程式庫以及其他的 Dll)。

  • 建置 MFC 擴充 DLL。 (請注意特殊旗標時,例如**_AFXEXT** ,用於建置擴充 DLL)

  • MFC 擴充 dll 的兩個範例。 其中一個會顯示有限的匯出 (TESTDLL1) 與 MFC 擴充 DLL 和匯出整個類別介面 (TESTDLL2) 的其他節目的基本結構。

用戶端應用程式和任何擴充 Dll 都必須使用相同版本的 MFCxx.DLL。 您應該遵循的慣例的 MFC DLL,並提供兩個偵錯和零售 (/ 釋放) 您的擴充 DLL 的版本。 這可讓用戶端程式能夠建置其應用程式的偵錯和零售版本,並將其連結與適當的偵錯] 或 [所有 dll 的零售版本。

注意事項注意事項

因為 C++ 命名為改變,而匯出的問題,從擴充 DLL 的 [匯出] 清單可能是不同的偵錯和零售版本的同一個 DLL 和 Dll 之間的不同平台。市售 MFCxx.DLL 已約 2000年匯出進入點。 MFCxxD.DLL 的偵錯已將大約 3000 匯出進入點。

hw85e4bb.collapse_all(zh-tw,VS.110).gif記憶體管理上的快速筆記

一節 〈 記憶體管理,"端附近的這份技術提示,說明使用 MFC 的共用版本 MFCxx.DLL 的實作。 本文所發動的只是擴充 DLL 所需的資訊。

MFCxx.DLL 與所有已載入到用戶端應用程式的位址空間的擴充 Dll 會使用相同的記憶體配置器,需要載入資源功能和其他 MFC 的 「 全域 」 狀態如同它們是在同一個應用程式中。 這非常重要,因為非 MFC DLL 程式庫,並以靜態方式連結至 MFC 的標準 dll 裡做的正好相反,而且有它自己的記憶體集區的每個 DLL 配置。

如果擴充 DLL 會配置記憶體,則該記憶體可以自由地與其他應用程式配置的物件相互摻雜。 此外,如果使用共用的 MFC 程式庫的應用程式損毀,作業系統的保護會維持共用 DLL 任何其他 MFC 應用程式的完整性。

同樣的用戶端應用程式和所有 MFC 擴充 Dll,以及 MFCxx.DLL 本身之間亦共用其他的 「 全域 」 MFC 狀態,例如要載入資源,目前的可執行檔。

hw85e4bb.collapse_all(zh-tw,VS.110).gif建置擴充 DLL

您可用來建立 MFC 擴充 DLL 專案,即 AppWizard,它會自動產生適當的編譯器和連結器設定。 所以,也會產生DllMain ,您可以修改的函式。

如果您將現有專案轉換成 MFC 擴充 DLL,開始建立使用 MFC 的共用的版本的應用程式的標準規則,然後執行下列動作:

  • 新增 /D_AFXEXT 編譯器旗標。 在專案屬性] 對話方塊中,選取 [C/C++] 節點。 然後選取 [前置處理器] 類別目錄。 新增**_AFXEXT**來定義巨集] 欄位中,每個項目使用分號分隔。

  • 移除**/Gy**編譯器參數。 在專案屬性] 對話方塊中,選取 [C/C++] 節點。 然後選取程式碼產生的類別。 請確定未啟用 ["啟用函式階層連結 」 的選項。 這會讓更輕鬆地匯出類別,因為連結器並不會移除未參考的函式。 如果原始的專案用來以靜態方式建置標準 DLL 連結至 MFC 中,變更 /MT [d 編譯器選項來 /MD [d

  • 建置匯出程式庫 /DLL 選項來連結。 當您建立一個新的目標,把 Win32 動態連結程式庫指定成目標型別時,這將會設定。

hw85e4bb.collapse_all(zh-tw,VS.110).gif變更您的標頭檔

其目標 DLL 是擴充的匯出某個一般功能,可以使用該功能的一或多個應用程式。 這能夠匯出類別和全域函式可供用戶端應用程式。

若要執行這項操作,您必須確保每個成員函式會標記為匯入或匯出適當地。 這需要特殊的宣告: __declspec(dllexport)__declspec(dllimport)。 當用戶端應用程式使用您的類別時,您想要被宣告為 __declspec(dllimport)。 當建置擴充 DLL 本身後時,他們應該宣告成 __declspec(dllexport)。 此外,必須是實際匯出函式,以便在載入期間用戶端程式繫結至它們。

若要匯出整個類別,請使用 AFX_EXT_CLASS 類別定義中。 此巨集由架構當做定義 __declspec(dllexport)_AFXDLL 和**_AFXEXT已定義,但被定義為 __declspec(dllimport)_AFXEXT**未定義。 _AFXEXT建置您的擴充 DLL 時,只能定義如前文所述。 例如:

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

hw85e4bb.collapse_all(zh-tw,VS.110).gif不要匯出整個類別

有時候您可能要匯出剛剛所需的個別成員您的類別。 例如,如果您正在匯出 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 的 Helper 巨集實際上會宣告或定義資料成員。 因此,這些資料成員也必須從您的 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 已經定義這種方式。 您只需要 re-define AFX_DATA一樣是 AFX_EXT_CLASS 解決您的類別定義。

例如:

   #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

注意事項注意事項

如果您是匯出整個類別而不是類別中選取的成員,則靜態資料成員會自動匯出。

您可以使用相同的技巧,來自動匯出CArchive引出運算子的類別使用DECLARE_SERIALIMPLEMENT_SERIAL巨集。 Bracketing 類別宣告,將匯出的封存運算子 (位於。H 檔案中) 與下列程式碼:

#undef AFX_API
#define AFX_API AFX_EXT_CLASS

<your class declarations here>

#undef AFX_API
#define AFX_API

hw85e4bb.collapse_all(zh-tw,VS.110).gif_AFXEXT 的限制

您可以使用下列 _AFXEXT 您的擴充 Dll 的前提是您不需要多重層級的擴充 Dll 的前置處理器符號。 如果您的擴充 DLL 呼叫或衍生自您自己之擴充 DLL 裡的類別,接著又衍生自 MFC 類別,您必須使用自己的前置處理器符號來避免模稜兩可 (Ambiguity) 的情形。

問題是因為您必須在 Win32 中將任何從 DLL 匯出的資料明確地宣告為 __declspec(dllexport),而在從 DLL 匯入則宣告為 __declspec(dllimport)。 當您定義 _AFXEXT 時,MFC 標頭檔會確定 AFX_EXT_CLASS 已正確地定義。

當您有多重層級、 一個符號例如 AFX_EXT_CLASS 是不夠,因為擴充 DLL 可能會被匯出新的類別,以及從另一台擴充程式 DLL 匯入其他類別。 若要處理這個問題,請使用特殊的前置處理器符號,指示您在建置 DLL 本身而非使用 DLL。 例如,假設有兩個擴充 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,建置 A.DLL 時匯出並匯入使用 B.DLL (或其他用戶端) 時。

使用內建時,就無法執行這種類型的分層 AFX_EXT_CLASS 和**_AFXEXT**前置處理器符號。 上面所述的技術可以解決這個問題的方式與不建置其 OLE、 資料庫及網路的擴充 Dll 時,會使用 MFC 本身的機制。

hw85e4bb.collapse_all(zh-tw,VS.110).gif不要匯出整個類別

同樣地,您必須在您不匯出整個類別時需要特別注意。 您必須確定已正確匯出 MFC 巨集所建立的必要資料項目。 這可透過 re-defining 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

hw85e4bb.collapse_all(zh-tw,VS.110).gifDllMain

以下是您應該將您的主要原始程式檔中,對您擴充程式 DLL 的實際程式碼。 它必須於標準包括之後。 請注意當您使用 AppWizard 建立擴充 DLL 的起始檔案時,會提供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擷取模組執行階段類別 (CRuntimeClass結構) 以及其物件工廠 (COleObjectFactory物件) 使用較新的修訂 CDynLinkLibrary 在建立物件。 (選擇性) 若要呼叫AfxTermExtensionModule MFC 清理擴充程式 DLL 時所允許每個處理序中斷連結 (當處理程序結束時,或當 DLL 已卸載的結果時,會發生的事 FreeLibrary 呼叫) 的擴充程式 DLL。 大部分的擴充 Dll 不會以動態方式載入後 (通常,它們連結透過其匯入程式庫),以呼叫AfxTermExtensionModule通常並不需要。

如果您的應用程式載入,並以動態方式釋出的擴充 Dll,就一定要呼叫AfxTermExtensionModule如上所示。 也請務必使用AfxLoadLibraryAfxFreeLibrary (而非 Win32 函式 LoadLibraryFreeLibrary) 如果您的應用程式使用多個執行緒,或以動態方式載入擴充 DLL。 使用AfxLoadLibraryAfxFreeLibrary確保擴充 DLL 會載入和卸載時所執行的啟動和關閉程式碼而損毀的全域 MFC 狀態。

AFXDLLX 標頭檔。H 包含特殊定義結構使用擴充 Dll,例如針對定義的AFX_EXTENSION_MODULECDynLinkLibrary

全域 extensionDLL 必須先宣告,如所示。 不同於 MFC 的 16 位元版本,您可以配置記憶體,並在此期間,呼叫 MFC 的函式,因為 MFCxx.DLL 完全初始化時您DllMain呼叫。

hw85e4bb.collapse_all(zh-tw,VS.110).gif共用資源和類別

簡單的 MFC 擴充 Dll 必須僅會匯出一些低頻寬的函式至用戶端應用程式,不多不少。 更多的使用者介面使用大量的 Dll 可能會想要匯出資源] 及 [C++ 類別,用戶端應用程式。

匯出資源是經由資源清單來完成。 在每個應用程式是單獨連結的串列的 CDynLinkLibrary 物件。 資源時,大部分的載入資源的標準 MFC 實作查看目前的資源模組 (AfxGetResourceHandle) 和 if 查核行程找不到清單中的 CDynLinkLibrary 嘗試載入要求的資源的物件。

動態建立 C++ 類別名稱的 C++ 物件很類似。 MFC 物件還原序列化機制必須具備的所有CRuntimeClass的物件登錄,讓它可以重新建構,經由動態建立所需的類型,根據已儲存的內容更早版本的 C++ 物件。

如果您想要使用您的擴充 DLL 中的類別,用戶端應用程式DECLARE_SERIAL,就必須要匯出類別,藉此將用戶端應用程式的 [看得見。 這也會帶您逐步完成 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 包含所有標準的 MFC 資源,包括所有的標準命令 Id 的提示字串。 把它放在清單的尾部讓 Dll 和用戶端應用程式本身沒有標準的 MFC 資源,但若要依賴 MFCxx.DLL 中的共用資源而是他們自己的複本。

用戶端應用程式的命名空間中併入的資源和所有 dll 的類別名稱有缺點,就是您必須要很小心何種識別碼或名稱。 您可以不用說關閉這個功能不會匯出任何一個資源 (含) CDynLinkLibrary 用戶端應用程式的物件。 DLLHUSK 範例會使用多個標頭檔來管理共用資源命名空間。 請參閱技術的附註 35 如需使用共用的資源檔的秘訣。

hw85e4bb.collapse_all(zh-tw,VS.110).gif正在初始化 DLL

如同前面所提到的您通常會想要建立 CDynLinkLibrary 以用戶端應用程式中匯出您的資源和類別的物件。 您必須提供初始化 DLL 匯出的進入點。 最小,這是虛值的常式會接受任何引數,並傳回執行任何動作,但它可以依自己的需求。

如果您使用這種方法,每個想要使用您的 DLL 的用戶端應用程式必須呼叫初始化常式中。 您可能還會配置這 CDynLinkLibrary 物件在您DllMain電話之後,只是AfxInitExtensionModule

在初始化常式必須建立 CDynLinkLibrary 中目前的應用程式的堆集 」 設定至剛才註冊您的擴充 DLL 資訊的物件。 這可以透過下列來完成:

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

常式的名稱, InitXxxDLL 在這個範例中,可以是任何您想要的項目。 不需要extern "C",但合作的話,使得容易維護的 [匯出] 清單。

注意事項注意事項

如果您使用您的擴充 DLL,由標準 DLL 時,您必須匯出這個初始設定函式。使用任何擴充功能 DLL 的類別或資源之前,必須從標準 DLL 中呼叫此函數。

hw85e4bb.collapse_all(zh-tw,VS.110).gif匯出的項目

匯出您的類別的簡單方法是使用 __declspec(dllimport)__declspec(dllexport) 上每個類別和您想要匯出的全域函式。 這可讓您更輕鬆,但不如命名 (說明如下) 每個進入點,因為您隨心所欲地掌控哪些函式會匯出,而且您無法依序數匯出函式。 TESTDLL1 和 TESTDLL2 使用這個方法,將匯出其項目。

更有效率的方法 (和 MFCxx.DLL 所使用的方法) 是以手動方式匯出每個項目,方法是透過指名的各個項目。DEF 檔。 因為我們要匯出選擇性匯出從我們的 DLL (亦即,並非所有功能),我們必須決定我們想要匯出哪一個特定的介面。 這很困難,因為您必須指定給連結器 mangled 的名稱,在表單中的項目。DEF 檔。 不要匯出任何 C++ 類別,除非您真的需要對此符號連結。

如果您已試過匯出 C++ 類別使用。DEF 檔之前,您可能想要開發工具,以便自動產生這份清單。 這可以使用兩階式連結的處理程序。 連結一次是使用沒有匯出,您的 DLL,並讓連結器來產生。對應檔。 。對應檔可以用來產生應匯出的函式的清單,與某些重新排列,它可以用來產生這些匯出項目,以讓您。DEF 檔。 MFCxx.DLL OLE 和幾千在數目、 資料庫擴充 Dll 的匯出清單是以這種處理程序產生的 (雖然它不是完全自動的並且需要某些手動調整每隔一段)。

hw85e4bb.collapse_all(zh-tw,VS.110).gifCWinApp vs。CDynLinkLibrary

MFC 擴充 DLL 並沒有CWinApp-衍生物件的練習。 而是必須使用的CWinApp-衍生的用戶端應用程式的物件。 這表示用戶端應用程式擁有主要訊息幫浦,閒置迴圈,以此類推。

如果您的 MFC 擴充 DLL 需要維護每個應用程式的額外資料,您可以衍生一個新的類別,從 CDynLinkLibrary 和常式上面所描述的 InitXxxDLL 來建立它。 該 DLL 會在執行時檢查 CDynLinkLibrary 物件目前的應用程式清單,找出特殊擴充 DLL 的物件。

hw85e4bb.collapse_all(zh-tw,VS.110).gif在您的 DLL 實作中使用資源

如同前面所提到的預設的資源負載將會引導清單 CDynLinkLibrary 尋找第一個 EXE 或 DLL 具有所要求的資源的物件。 所有 MFC Api,以及所有內部的程式碼會使用AfxFindResourceHandle逐一處理 [資源] 清單,以找出任何資源,則不論可能所在位置。

如果您想要只從特定位置中載入的資源,使用 Api AfxGetResourceHandleAfxSetResourceHandle儲存舊的控點,並設定新的控制代碼。 請確定在傳回用戶端應用程式之前要還原舊的資源控制代碼。 TESTDLL2 範例會使用這種方法,來明確載入一個功能表。

瀏覽清單時會出現速度略微緩慢和需要管理資源 ID 範圍等缺點。 優點是連結至數個擴充 DLL 的用戶端應用程式可以使用任何 DLL 提供的資源,而不需要指定 DLL 執行個體控制代碼 (Instance Handle)。 AfxFindResourceHandle 是 API,用來逐一查看資源清單以尋找指定的符合項目。 這個 API 會使用到資源的名稱、類型,並傳回第一次發現時 (或 NULL) 的資源控制代碼。

撰寫使用 DLL 版本的應用程式

hw85e4bb.collapse_all(zh-tw,VS.110).gif應用程式的需求

使用 MFC 的共用的版本的應用程式必須遵循幾個簡單的規則:

  • 您必須先將CWinApp物件,並依照訊息幫浦的標準規則。

  • 它必須使用一組必要的編譯器旗標 (如下所示) 進行編譯。

  • 它必須連結 MFCxx 匯入程式庫。 藉由設定必要的編譯器旗標,MFC 標頭在連結階段時決定哪一個應用程式應該使用連結的文件庫。

  • 若要執行可執行檔,MFCxx.DLL 必須在路徑上或 Windows 系統目錄中。

hw85e4bb.collapse_all(zh-tw,VS.110).gif與開發環境建置

如果您使用內部的 makefile,其中大部分的標準預設值,您可以輕鬆地變更要建置的 DLL 版本的專案。

下列步驟假設您擁有 NAFXCWD 與連結正常運作的 MFC 應用程式。LIB (適用於偵錯),NAFXCW。LIB (適用於零售版) 而您想要將它轉換成使用共用的 MFC 程式庫版本。 您正在執行 Visual C++ 環境,並有內部的專案檔案。

  1. 專案 ] 功能表中,按一下 屬性。 在一般 頁面下 專案預設值,Mfc 設為 使用 MFC 的共用 dll (MFCxx(d).dll)。

hw85e4bb.collapse_all(zh-tw,VS.110).gifNmake 會進行建置

如果您正在使用外部 makefile 」 功能的 Visual C++ 中,或直接使用 NMAKE 時,您將需要編輯您的 makefile,以支援編譯器和連結器選項

所需的編譯器旗標:

  • / D_AFXDLL /MD
    / D_AFXDLL

標準的 MFC 標頭必須要定義這個符號:

  • /MD
    應用程式必須使用 c 執行階段程式庫的 DLL 版本

所有其他編譯器旗標,請遵循 MFC 預設值 (例如,偵錯 _DEBUG)。

編輯文件庫連結器清單。 變更 NAFXCWD。LIB 來 MFCxxD.LIB 和 NAFXCW 的變更。LIB 來 MFCxx.LIB。 取代 LIBC。LIB 與 MSVCRT。LIB。 因為您與任何其他的 MFC 程式庫很重要放置 MFCxxD.LIB 之前的任何 c 執行階段程式庫。

選擇性地將加入 /D_AFXDLL 自己零售版和偵錯資源編譯器選項 (實際上會編譯與資源的那一個 /R)。 這樣最終執行檔較小的共用資源出現在 MFC Dll。

進行這些變更後,就需要完整重新建置。

hw85e4bb.collapse_all(zh-tw,VS.110).gif建置範例

您可以建立大多數的 MFC 程式範例,從 Visual C++ 或共用的 NMAKE 相容 MAKEFILE,從命令列。

若要轉換這些範例使用 MFCxx.DLL 的任何問題,您可以載入。MAK 到 Visual C++ 檔案,並設定專案選項,如上文所述。 如果您正在使用 NMAKE 組建,您可以指定"AFXDLL = 1"在 NMAKE 命令列,並將建置這個範例使用共用的 MFC 程式庫。

MFC 進階概念範例 DLLHUSK 由 MFC 的 DLL 版本所建立。 這個範例不只會說明如何建置應用程式連結的 MFCxx.DLL,但它也說明了 MFC DLL 封裝選項,例如,這份技術提示稍後所述的 MFC 擴充 Dll 的其他功能。

hw85e4bb.collapse_all(zh-tw,VS.110).gif封裝備忘稿

零售版的 dll (MFCxx [U]。DLL) 自由轉散發。 偵錯版本的 dll 沒有自由可轉散發,而且應該只有在您的應用程式開發期間使用。

偵錯資訊會提供 Dll 的偵錯。 藉由使用 Visual C++ 偵錯工具,您會發現您的應用程式,以及該 DLL 的執行。 發行版本的 Dll (MFCxx [U]。DLL) 並不會包含偵錯資訊。

如果您自訂或重新建置 Dll 時,然後您應該呼叫這些東西 MFC SRC"MFCxx"檔 MFCDLL 以外。MAK 將告訴您的建置選項,並包含重新命名該 DLL 的邏輯。 重新命名檔案是必要的因為這些 Dll 可能由許多 MFC 應用程式共享。 讓您自訂的版本的 MFC Dll 取代系統上已安裝的可能會中斷使用共用的 MFC Dll 的另一台 MFC 應用程式。

建議您不要重新建置 MFC Dll。

MFCxx.DLL 的實作方式

下節將說明 MFC DLL (MFCxx.DLL 和 MFCxxD.DLL) 的實作方式。 了解的詳細資料也不很重要,若您想要進行是與應用程式中使用 MFC DLL。 這裡沒有必要讓您瞭解如何撰寫 MFC 擴充 DLL,但是了解這項實作可以幫助您撰寫您自己的 DLL。

hw85e4bb.collapse_all(zh-tw,VS.110).gif實作概觀

如前文所述,MFC DLL 其實 MFC 擴充 DLL 是特例。 它有非常大量的類別是大量的匯出。 有幾個其他一些項目進行這個動作 MFC DLL,可讓您更特殊比標準的擴充 DLL。

hw85e4bb.collapse_all(zh-tw,VS.110).gifWin32 會負責大部分的工作

MFC 的 16 位元版本所需的幾種特殊的技術,包括每個應用程式上的資料在堆疊區段內,一些 80x86 組件程式碼、 每個處理序的例外狀況內容和其他技術所建立的特殊區段。 Win32 直接支援同處理序資料在 DLL 中,也就是您想採用大部份的時間。 大多數的情況下 MFCxx.DLL 是只是 NAFXCW。LIB 會封裝於 DLL 中。 如果您查看 MFC 原始程式碼時,您會發現很少的 # ifdef _AFXDLL,因為有很少需要進行的特殊情況。 會有專門處理 Windows 3.1 (亦稱為 win32 中) 上的 Win32 特殊案例。 Win32 中並不支援同處理序 DLL 資料,所以 MFC DLL 必須使用執行緒區域儲存區 (TLS) 來取得本機資料的處理程序的 Win32 Api 直接。

hw85e4bb.collapse_all(zh-tw,VS.110).gif在文件庫的來源,額外的檔案上的影響

所造成的影響 _AFXDLL 上標準的 MFC 類別程式庫來源和標頭版本則幅度不大。 沒有特殊版本檔案 (AFXV_DLL。H),以及其他的標頭檔 (AFXDLL_。H) 中加入包含主要的 AFXWIN。H 標頭。 AFXDLL_。H 標頭包含了 CDynLinkLibrary 類別和其他實作細節兩者的 _AFXDLL 應用程式與 MFC 擴充 Dll。 AFXDLLX。H 標頭被提供來建置 MFC 擴充 Dll (如需詳細資訊請見上述)。

在 MFC SRC MFC 程式庫的一般來源有額外的條件式程式碼在 _AFXDLL # ifdef。 其他的原始程式檔 (DLLINIT。CPP) 裡包含額外的初始化程式碼和其他使用 MFC 的共用版本黏附。

若要建立 MFC 的共用的版本,提供額外的檔案。 (看到下面如需如何建置 DLL 的詳細資訊)。

  • 兩個。DEF 檔用來匯出偵錯 (MFCxxD.DEF) 中的 MFC DLL 的進入點,然後放開 (MFCxx.DEF) 版本的 DLL。

  • 某個。RC 檔 (MFCDLL。RC) 會包含所有標準的 MFC 資源和 VERSIONINFO 資源 dll。

  • 答:。CLW 檔案 (MFCDLL。若要允許瀏覽的 MFC 類別使用類別精靈提供 CLW)。 注意: 這項功能不是 MFC 的 DLL 版本的特殊的。

hw85e4bb.collapse_all(zh-tw,VS.110).gif記憶體管理

使用 MFCxx.DLL 的應用程式會使用一般的記憶體配置器所提供的 MSVCRTxx.DLL,共用的 c 執行階段 DLL。 應用程式、 任何擴充 Dll,以及 MFC Dll 本身以及使用此共用的記憶體配置器。 藉由使用共用的 DLL 進行記憶體配置時,MFC Dll 可以配置的應用程式,或反之,稍後會釋放的記憶體。 因為應用程式和 DLL 都必須使用相同的配置器,您不應該覆寫 C++ 全域operator newoperator delete。 相同的規則套用到 c 執行階段記憶體配置常式的其餘部分 (例如mallocrealloc免費,等等)。

hw85e4bb.collapse_all(zh-tw,VS.110).gif序數和類別 __declspec(dllexport) 和 DLL 命名

我們不會使用class**__declspec(dllexport)** C++ 編譯器的功能。 相反地,匯出的清單會包含的類別程式庫來源 (MFCxx.DEF 和 MFCxxD.DEF)。 只有這些組選定的進入點 (函式和資料) 會匯出。 其他符號,例如 MFC 私用實作函式或類別,並不會匯出所有的匯出完成根據序數而不是內建或非駐留名稱資料表中的字串名稱。

使用class**__declspec(dllexport)** 可能是可行的替代方案建置較小的 Dll,但如果是大型的 DLL 和匯出機制的預設值,MFC 一樣具有效率與容量限制。

上述這是功能的什麼我們可以將封裝了大量的版本只是功能的大約 800 KB,而不會危害執行太多,或載入速度的 MFCxx.DLL 中。 MFCxx.DLL 本來應該是較大 100k 這項技術不被使用。 這也讓它可以在結尾處加入額外的進入點。DEF 檔,而不會危害速度和大小的效率依序數匯出允許簡單的版本控制。 MFC 類別庫中的主要版本修訂將會變更文件庫名稱。 也就是 MFC30。DLL 是包含 MFC 類別程式庫 3.0 版可轉散發 DLL。 升級的 DLL,說,假設性的 MFC 3.1,DLL 會命名為 MFC31。DLL 相反。 同樣地,如果您修改 MFC 原始程式碼來產生自訂版本的 MFC DLL,使用不同的名稱 (,最好是另一個不是以 「 MFC") 在 [名稱]。

請參閱

其他資源

技術的備忘稿編號

依類別的技術注意事項