DLL类型 |
入口函数 |
非 MFC DLL |
编程者提供DllMain函数 |
MFC规则 DLL |
CWinApp对象的InitInstance 和 ExitInstance |
MFC扩展 DLL |
MFC DLL向导生成DllMain 函数 |
对于MFC扩展DLL,
系统会自动在工程中添加如下表所示的宏,这些宏为DLL和应用程序的编写提供了方便。像AFX_EXT_CLASS、AFX_EXT_API、AFX_EXT_DATA这样的宏,在DLL和应用程序中将具有不同的定义,这取决于_AFXEXT宏是否被定义。这使得在DLL和应用程序中,使用统一的一个宏就可以表示出输出和输入的不同意思。在DLL中,表示输出(因为_AFXEXT被定义,通常是在编译器的标识参数中指定/D_AFXEXT);在应用程序中,则表示输入(_AFXEXT没有定义)。
宏 |
定义 |
AFX_CLASS_IMPORT |
__declspec(dllexport) |
AFX_API_IMPORT |
__declspec(dllexport) |
AFX_DATA_IMPORT |
__declspec(dllexport) |
AFX_CLASS_EXPORT |
__declspec(dllexport) |
AFX_API_EXPORT |
__declspec(dllexport) |
AFX_DATA_EXPORT |
__declspec(dllexport) |
AFX_EXT_CLASS |
#ifdef _AFXEXT AFX_CLASS_EXPORT #else AFX_CLASS_IMPORT |
AFX_EXT_API |
#ifdef _AFXEXT AFX_API_EXPORT #else AFX_API_IMPORT |
AFX_EXT_DATA |
#ifdef _AFXEXT AFX_DATA_EXPORT #else AFX_DATA_IMPORT |
6.2 MFC扩展DLL导出MFC派生类
在这个例子中,我们将产生一个名为“ExtDll”的MFC扩展DLL工程,在这个DLL中导出一个对话框类,这个对话框类派生自MFC类CDialog。
使用MFC向导生成MFC扩展DLL时,系统会自动添加如下代码:
static AFX_EXTENSION_MODULE ExtDllDLL = { NULL, NULL }; extern "C" int APIENTRY
DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved ) { // Remove this if you use lpReserved
UNREFERENCED_PARAMETER( lpReserved );
//说明:lpReserved是一个被系统所保留的参数,对于隐式链接是一个非零值,对于显式链接值是零
if (dwReason == DLL_PROCESS_ATTACH) { TRACE0( "EXTDLL.DLL Initializing! " ); // Extension DLL one-time initialization if ( !AfxInitExtensionModule( ExtDllDLL, hInstance )) return 0; // Insert this DLL into the resource chain new CDynLinkLibrary( ExtDllDLL ); } else if (dwReason == DLL_PROCESS_DETACH) { TRACE0( "EXTDLL.DLL Terminating! " ); // Terminate the library before destructors are called AfxTermExtensionModule( ExtDllDLL ); } return 1; // ok } 这一段代码含义晦涩,我们需要对其进行解读:
(1)上述代码完成MFC扩展DLL的初始化和终止处理;
(2)初始化期间所创建的 CDynLinkLibrary 对象使MFC扩展 DLL 可以将 DLL中的CRuntimeClass 对象或资源导出到应用程序;
(3)AfxInitExtensionModule函数捕获模块的CRuntimeClass 结构和在创建 CDynLinkLibrary 对象时使用的对象工厂(COleObjectFactory 对象);
(4)AfxTermExtensionModule函数使 MFC 得以在每个进程与扩展 DLL 分离时(进程退出或使用AfxFreeLibrary卸载DLL时)清除扩展 DLL;
(5)第一条语句static AFX_EXTENSION_MODULE ExtDllDLL = { NULL, NULL };定义了一个AFX_EXTENSION_MODULE类的静态全局对象,AFX_EXTENSION_MODULE的定义如下:
struct AFX_EXTENSION_MODULE { BOOL bInitialized; HMODULE hModule; HMODULE hResource; CRuntimeClass* pFirstSharedClass; COleObjectFactory* pFirstSharedFactory; }; 由AFX_EXTENSION_MODULE的定义我们可以更好的理解(2)、(3)、(4)点。
在资源编辑器中添加一个如图15所示的对话框,并使用MFC类向导为其添加一个对应的类CExtDialog,系统自动添加了ExtDialog.h和ExtDialog.cpp两个头文件。
图15 MFC扩展DLL中的对话框 |
修改ExtDialog.h中CExtDialog类的声明为:
class AFX_EXT_CLASS CExtDialog : public CDialog { public: CExtDialog( CWnd* pParent = NULL ); enum { IDD = IDD_DLL_DIALOG }; protected: virtual void DoDataExchange( CDataExchange* pDX ); DECLARE_MESSAGE_MAP() }; 这其中最主要的改变是我们在class AFX_EXT_CLASS CExtDialog语句中添加了“AFX_EXT_CLASS”宏,则使得DLL中的CExtDialog类被导出。
6.3 MFC扩展DLL的加载
6.3.1 隐式加载
我们在6.2工程所在的工作区中添加一个LoadExtDllDlg工程,用于演示MFC扩展DLL的加载。在LoadExtDllDlg工程中添加一个如图16所示的对话框,这个对话框上包括一个“调用DLL”按钮。
图16 MFC扩展DLL调用工程中的对话框 |
在与图16对应对话框类实现文件的头部添加:
// LoadExtDllDlg.cpp : implementation file //
#include "..ExtDialog.h" #pragma comment( lib, "ExtDll.lib" )
而“调用DLL”按钮的单击事件的消息处理函数为:
void CLoadExtDllDlg::OnDllcallButton() { CExtDialog extDialog; extDialog.DoModal(); } 当我们单击“调用 |