分享方式:


在 MFC DLL 中使用資料庫、OLE 和通訊端 MFC 延伸模組 DLL

從一般 MFC DLL 使用 MFC 擴充 DLL 時,如果 MFC 擴充功能 DLL 未連線到 CDynLinkLibrary 一般 MFC DLL 的物件鏈結,您可能會遇到一或多個相關問題。 因為 MFC 資料庫、OLE 和通訊端的偵錯版本支援 DLL 實作為 MFC 擴充 DLL,因此如果您使用這些 MFC 功能,您可能會看到類似的問題,即使您未明確使用任何 MFC 擴充功能 DLL 也一樣。 以下是一些徵兆:

  • 嘗試還原序列化 MFC 擴充 DLL 中所定義類別類型的物件時,訊息「警告:無法從封存載入 CYourClass」訊息。 類別未定義。「 會出現在 TRACE 偵錯視窗中,而且物件無法序列化。

  • 表示可能會擲回錯誤類別的例外狀況。

  • 儲存在 MFC 擴充功能 DLL 中的資源無法載入,因為 AfxFindResourceHandle 傳回 NULL 或資源控制碼不正確。

  • DllGetClassObjectDllCanUnloadNow 、 和 UpdateRegistry RevokeAll Revoke 、 和 RegisterAll 成員函 COleObjectFactory 式找不到 MFC 擴充 DLL 中定義的類別處理站。

  • AfxDoForAllClasses 不適用於 MFC 擴充 DLL 中的任何類別。

  • 標準 MFC 資料庫、通訊端或 OLE 資源無法載入。 例如, AfxLoadString(AFX_IDP_SQL_CONNECT_FAIL) 即使一般 MFC DLL 正確使用 MFC 資料庫類別,也會傳回空字串。

這些問題的解決方案是在建立物件之 MFC 擴充 DLL CDynLinkLibrary 中建立和匯出初始化函式。 從每一個使用 MFC 擴充 DLL 的一般 MFC DLL,呼叫這個初始化函式一次。

MFC OLE、MFC 資料庫(或 DAO)或 MFC 通訊端支援

如果您在一般 MFC DLL 中使用任何 MFC OLE、MFC 資料庫(或 DAO)或 MFC 通訊端支援,則 MFC 偵錯 MFC 擴充 DLL MFCOxxD.dllMFCDxxD.dllMFCNxxD.dll (其中 xx 是版本號碼) 會自動連結。 針對您使用的每個 DLL 呼叫預先定義的初始化函式:

  • 如需資料庫支援,請在其 CWinApp::InitInstance 函式中新增對一般 MFC DLL 的呼叫 AfxDbInitModule 。 請確定此呼叫發生在任何基類呼叫之前,或存取 MFCDxxD.dll 的任何新增程式碼。 此函式不接受任何參數並傳 void 回 。

  • 若為 OLE 支援,請將 呼叫新增至一般 MFC DLL 的 CWinApp::InitInstanceAfxOleInitModule 式。 函式 COleControlModule::InitInstance 已經呼叫 AfxOleInitModule ,因此如果您要建置 OLE 控制項並使用 COleControlModule ,則不應該將此呼叫新增至 AfxOleInitModule

  • 針對 Sockets 支援,在 中 CWinApp::InitInstance 將 的呼叫 AfxNetInitModule 新增至您的一般 MFC DLL。

MFC DLL 和應用程式的發行組建不會針對資料庫、通訊端或 OLE 支援使用不同的 DLL。 不過,在發行模式中呼叫這些初始化函式是安全的。

CDynLinkLibrary 物件

在本文開頭提及的每個作業期間,MFC 必須搜尋特定值或物件。 例如,在還原序列化期間,MFC 必須搜尋所有目前可用的執行時間類別,以符合封存中的物件及其適當的執行時間類別。

作為這些搜尋的一部分,MFC 會藉由走動物件鏈 CDynLinkLibrary 來掃描使用中的所有 MFC 擴充 DLL。 CDynLinkLibrary 物件會在建構期間自動附加至鏈結,並在初始化期間由每個 MFC 擴充 DLL 所建立。 每個模組 (應用程式或一般 MFC DLL) 都有自己的物件鏈 CDynLinkLibrary 結。

若要讓 MFC 擴充 DLL 連線到 CDynLinkLibrary 鏈結中,它必須在使用 MFC 擴充 DLL 的每個模組內容中建立 CDynLinkLibrary 物件。 若要在一般 MFC DLL 中使用 MFC 擴充 DLL,延伸模組 DLL 必須提供匯出的初始化函式來建立 CDynLinkLibrary 物件。 每一個使用 MFC 延伸模組 DLL 的一般 MFC DLL 都必須呼叫匯出的初始化函式。

如果您只會從 MFC 應用程式使用 MFC 擴充 DLL,且永遠不會使用一般 MFC DLL,則足以在 MFC 擴充功能 DLL DllMain 函式中建立 CDynLinkLibrary 物件。 這是 MFC DLL 精靈 MFC 擴充功能 DLL 程式碼的功能。 以隱含方式載入 MFC 擴充功能 DLL 時, DllMain 會在應用程式啟動之前載入和執行。 任何 CDynLinkLibrary 建立專案會連線到 MFC DLL 保留給 MFC 應用程式的預設鏈結中。

在任何一個鏈結中,從一個 MFC 擴充 DLL 有多個 CDynLinkLibrary 物件是個壞主意。 如果 MFC 擴充功能 DLL 可能會從記憶體動態卸載,則特別如此。 請勿從任何一個模組多次呼叫初始化函式。

範例程式碼

此範例程式碼假設一般 MFC DLL 隱含連結至 MFC 擴充 DLL。 若要隱含連結,請在建置一般 MFC DLL 時,連結到 MFC 擴充 DLL 的匯入程式庫 (LIB 檔案)。

下列幾行應該位於 MFC 擴充 DLL 的來源中:

// YourExtDLL.cpp:

// standard MFC extension DLL routines
#include "afxdllx.h"

static AFX_EXTENSION_MODULE extensionDLL;

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

// Exported DLL initialization is run in context of
// application or regular MFC DLL
extern "C" void WINAPI InitYourExtDLL()
{
    // create a new CDynLinkLibrary for this app
    new CDynLinkLibrary(extensionDLL);

    // add other initialization here
}

請務必匯出 InitYourExtDLL 函式。 您可以使用 __declspec(dllexport) ,或在 DLL 的 DEF 檔案中匯出它,如下所示:

// YourExtDLL.Def:
LIBRARY      YOUREXTDLL
CODE         PRELOAD MOVEABLE DISCARDABLE
DATA         PRELOAD SINGLE
EXPORTS
    InitYourExtDLL

使用 MFC 擴充 DLL,在每個一般 MFC DLL 中新增衍生物件成員 CWinApp 的呼叫 InitInstance

// YourRegularDLL.cpp:

class CYourRegularDLL : public CWinApp
{
public:
    virtual BOOL InitInstance(); // Initialization
    virtual int ExitInstance();  // Termination

    // nothing special for the constructor
    CYourRegularDLL(LPCTSTR pszAppName) : CWinApp(pszAppName) { }
};

BOOL CYourRegularDLL::InitInstance()
{
    // any DLL initialization goes here
    TRACE0("YOUR regular MFC DLL initializing\n");

    // wire any MFC extension DLLs into CDynLinkLibrary chain
    InitYourExtDLL();

    return TRUE;
}

您想要做什麼事?

您還想知道關於哪些方面的詳細資訊?

另請參閱

MFC 延伸模組 DLL