创建简单的加载时 DLL
本文介绍了如何使用 Microsoft Foundation Class 和 Win32 API 创建简单的加载时 DLL
引言
如果您想创建模块化软件,那么您会选择 DLL。与应用程序相比,动态链接库更容易创建。动态链接库是一组包含函数或其他称为 DLL 的模块的集合。
在 Windows 操作系统中,一些 DLL 非常重要。它们如下:User32.dll 管理与用户界面相关的任务。Gdi32.dll 管理图形设备接口 (GDI) 相关的任务。在 DOS 世界中,程序直接写入视频内存。但在 Windows 层存在一个名为图形设备接口 (GDI) 的组件。advapi32.dll 管理与注册表相关的任务。comdlg32.dll 管理与通用对话框相关的任务(例如文件打开对话框、文件保存和另存为对话框)。comctrl32.dll 管理 Windows 通用控件相关的任务。
Windows DLL 是 Windows 操作系统的骨干。Windows 操作系统管理着大量的系统 DLL。当 Windows 操作系统启动时,DLL 会加载到系统内存中。
DLL 的类型
Windows 操作系统有两种类型的 DLL。它们如下。
- 加载时动态链接
- 运行时动态链接
加载时动态链接在加载时加载 DLL。当应用程序启动时,所有必需的 DLL 都会在启动时加载到内存中。在此方法中,系统会尝试在以下位置查找 DLL。
- Windows 系统目录
- Windows 目录
- 应用程序本地路径
- PATH 环境变量中列出的目录
加载时 DLL 在创建应用程序时需要 LIB 文件和声明文件(.h)。我们在应用程序中插入头文件,并在应用程序项目设置中链接 LIB 文件。DLL 不处理 Windows 消息。DLL 只是在声明文件(.h)中声明并在实现文件(.cpp)中实现的一组函数或变量。
运行时动态链接尝试在运行时加载 DLL。LoadLibrary
函数用于在运行时加载 DLL。LoadLibrary
的语法如下。
HINSTANCE hinst = LoadLibrary(LPCTSTR dllfilename);
如果 LoadLibrary
返回成功,那么我们使用 GetProcAddress
获取函数的地址。调用 DLL 函数后,我们调用 FreeLibrary
来释放 DLL 库。在这种运行时动态链接中,我们不会在启动时加载所有 DLL 文件。无论何时需要,我们都会加载和卸载 DLL。
创建加载时 Win32 DLL
我们已经看到,使用 DLL 可以轻松创建模块化应用程序。在 Win32 动态链接库项目中,选择 DLL 并在第二步添加对某些导出符号的支持。在该类声明中添加您的方法和返回类型。当您在 DLL 文件中分配内存时,也要对其进行释放。如果您在客户端(例如应用程序)中释放内存,它可能会被释放,但我们不能确定。
__declspec(dllimport)
告诉编译器添加一些用于从 DLL 导入的符号。这样,__declspec(dllexport)
告诉编译器导出一些符号。在我们的示例程序中,声明了三个函数。这些函数用于将两个值相加、相乘和相减。这些简单的 DLL 有助于您理解基本的 DLL 功能。
DLL 的入口点是 DllMain
;DllMain
的语法如下。
BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { switch( ul_reason_for_call ) { case DLL_PROCESS_ATTACH: . . case DLL_THREAD_ATTACH: . . case DLL_THREAD_DETACH: . . case DLL_PROCESS_DETACH: . . } return TRUE; }
将 DLL 文件复制到系统目录,将 LIB 文件复制到 Visual C++ Lib 目录并链接到 lib 文件。在应用程序模块中,确保实现头文件。在我们的示例中,文件声明如下:
#ifdef WIN32DLL_EXPORTS #define WIN32DLL_API __declspec(dllexport) #else #define WIN32DLL_API __declspec(dllimport) #endif // This class is exported from the Win32DLL.dll class WIN32DLL_API CWin32DLL { public: CWin32DLL(void); // TODO: add your methods here. int add(int a,int b); int sub(int a,int b); int mul(int a,int b); }; extern WIN32DLL_API int nWin32DLL;
类 CWin32DLL
已使用 WIN32DLL_API
声明为 __declspec(dllexport)
。因此,所有类成员函数和成员变量都是 __declspec(dllexport)
。所有成员函数都声明为 public
。
在我们的实现文件中,我们链接并调用函数。
客户端程序中的运行时动态链接如下。#include "stdio.h" #include "windows.h" typedef VOID (*MYPROC)(LPTSTR); VOID main(VOID) { HINSTANCE hinstLib; MYPROC ProcAdd; BOOL fFreeResult, fRunTimeLinkSuccess = FALSE; // Get a handle to the DLL module. hinstLib = LoadLibrary("win32dll.dll"); // If the handle is valid, try to get the function address. if (hinstLib != NULL) { ProcAdd = (MYPROC) GetProcAddress(hinstLib, "add"); // Do add operation // If the function address is valid, call the function. if (fRunTimeLinkSuccess = (ProcAdd != NULL)) (ProcAdd) ("message via DLL function\n"); // Free the DLL module. fFreeResult = FreeLibrary(hinstLib); } // If unable to call the DLL function, use an alternative. if (! fRunTimeLinkSuccess) printf("message via alternative method\n"); }
创建 MFC DLL
Microsoft 基础类 (MFC) 库可用于创建简化的 DLL。MFC 支持两种类型的 DLL。它们如下。
- 使用 MFC 静态链接的常规 DLL
- 使用共享 MFC DLL 的常规 DLL
- MFC 扩展 DLL(使用共享 MFC DLL)
在 MFC 静态链接的常规 DLL 中,客户端可以是基于 MFC 的应用程序或非 MFC 应用程序。我们的示例程序应用程序基于使用共享 MFC DLL 的 DLL。
MFC 扩展 DLL 包含从现有 Microsoft 基础类派生的可重用类。扩展 DLL 是从 DLL 的动态链接库版本构建的。在 MFC 中,常规 DLL 有三种初始化方式。DLL 具有 CWinApp
对象。MFC OLE 使用全局 AfxOleInitModule
函数进行初始化。MFC 数据库使用全局 AfxDbInitModule
函数初始化到 MFC。MFC 套接字使用 AfxNetInitModule
函数进行初始化。
扩展 DLL 的初始化如下。
extern "C" int APIENTRY DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) { if (dwReason == DLL_PROCESS_ATTACH) { // test.dll Initializing! // Extension DLL one-time initialization AfxInitExtensionModule(PROJNAMEDLL, hInstance); // Insert this DLL into the resource chain new CDynLinkLibrary(dll); } else if (dwReason == DLL_PROCESS_DETACH) { // test.dll Terminating! } return 1; // ok }
在我们的示例中,DLL 具有 DrawEllipse
函数。我们将 CRect
结构和 CDC
传递给 DLL。DLL 函数使用选定的蓝色画笔绘制 DLL。
DLL 的优点
使用 DLL 的好处如下。
- 动态链接库共享内存。因此,与使用应用程序相比,系统性能有所提高。
- 我们可以单独构建和测试每个 DLL。
- 我们可以创建不同语言的 DLL。Windows 使用 C DLL、C++ DLL、Fortran DLL 和 PASCAL DLL 等。甚至 Windows 也支持某些版本的小型语言 DLL。
- 我们可以在运行时加载和卸载。这有助于提高应用程序性能。
- 大型软件产品被划分为多个 DLL。开发人员可以轻松地开发他们的应用程序。