在规则 MFC DLL 中使用数据库、OLE 和套接字 MFC 扩展 DLL
从规则 MFC DLL 使用 MFC 扩展 DLL 时,如果 MFC 扩展 DLL 未连接到规则 MFC DLL 的 CDynLinkLibrary
对象链中,则可能会遇到一个或多个相关问题。 由于 MFC 数据库、OLE 和套接字支持 DLL 的调试版本是以 MFC 扩展 DLL 的形式实现,因此,如果你使用这些 MFC 功能,即使未显式使用你自己的任何 MFC 扩展 DLL,也可能会遇到类似问题。 一些症状如下:
尝试反序列化 MFC 扩展 DLL 中定义的类类型的对象时,消息“警告:无法从存档加载 CYourClass。 未定义的类。"出现在跟踪调试窗口中,对象无法序列化。
可能会引发指示类错误的异常。
由于
AfxFindResourceHandle
返回NULL
或不正确的资源句柄,因此存储在 MFC 扩展 DLL 中的资源无法加载。DllGetClassObject
、DllCanUnloadNow
以及RegisterAll
的UpdateRegistry
、Revoke
、RevokeAll
和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.dll
、MFCDxxD.dll
和 MFCNxxD.dll
(其中 xx 是版本号)。 为所使用的每个 DLL 调用预定义初始化函数:
对于数据库支持,将对
AfxDbInitModule
的调用添加到CWinApp::InitInstance
函数中的规则 MFC DLL。 确保在任何基类调用或任何访问MFCDxxD.dll
的已添加代码之前进行此调用。 此函数不采用任何参数并返回void
。对于 OLE 支持,将对
AfxOleInitModule
的调用添加到CWinApp::InitInstance
中的规则 MFC DLL。COleControlModule::InitInstance
函数已调用AfxOleInitModule
,因此如果你正在生成 OLE 控件并且使用COleControlModule
,则不应将此调用添加到AfxOleInitModule
。对于套接字支持,将对
AfxNetInitModule
的调用添加到CWinApp::InitInstance
中的规则 MFC DLL。
MFC DLL 和应用程序的发布版本不将单独的 DLL 用于数据库、套接字或 OLE 支持。 但是,在发布模式下可安全地调用这些初始化函数。
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;
}