📄 1.txt
字号:
9.3创建动态连接库
在一些情况下,必须使用动态连接库:
1.多个应用程序共享代码和数据:比如Office软件的各个组成部分有相似的外观和功能,这就是通过共享动态连接库实现的。
2.在钩子程序过滤系统消息时必须使用动态连接库
3.设备驱动程序必须是动态连接库
4.如果要在对话框编辑器中使用自己定义的控件,也必须使用动态连接库
5.动态连接库以一种自然的方式将一个大的应用程序划分为几个小的模块,有利于小组内部成员的分工与合作。而且,各个模块可以独立升级。如果小组中的一个成员开发了一组实用例程,他就可以把这些例程放在一个动态连接库中,让小组的其他成员使用。
6.为了实现应用程序的国际化,往往需要使用动态连接库。使用动态连接库可以将针对某一国家、语言的信息存放在其中。对于不同的版本,使用不同的动态连接库。在使用AppWizard生成应用程序时,我们可以指定资源文件使用的语言,这就是通过提供不同的动态连接库实现的。
MFC支持两类动态连接库的创建:
用户动态连接库
MFC扩展类库。
9.3.1用户动态连接库(_USRDLL)
用户动态连接库一般使用C语言接口。要创建一个动态连接库,选择File->New菜单,弹出New对话框。在Projects标签页下,选择“Win32 Dynamic-Link Library”。Visual C++就会创建动态连接库所需的工程文件和MAK文件。
然后把下面两个文件加入到工程中(Project-Add to Project-Files菜单)。
文件1:mymaths.cpp
////////////////////////////
//mymaths.cpp
//
//a maths API DLL.
//
///////////////////////////
#include<windows.h>
//Declare the DLL functions prototypes
int Summary(int);
int Factorial(int);
//////////////////////////
//DllEntryPoint():The entry point of the DLL
//
/////////////////////////
BOOL WINAPI DLLEntryPoint(HINSTANCE hDLL,DWORD dwReason,
LPVOID Reserved)
{
switch(dwReason)
{
case DLL_PROCESS_ATTACH:
{
//一些初始化代码
break;
}
case DLL_PROCESS_DETACH:
{
//一些用于清理的代码
break;
}
}
return TRUE;
}
int Summary(int n)
{
int sum=0;
int i;
for(i=1;i<=n;i++)
{
sum+=i;
}
return sum;
}
int Factorial(int n)
{
int Fact=1;
int i;
for(i=1;i<=n;i++)
{
Fact=Fact*i;
}
return Fact;
}
文件2:mymaths.def
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Mymaths.DEF
;
;The DEF file for the Mymaths.DLL DLL.
;
LIBRARY mymaths
CODE PRELOAD MOVEABLE DISCARDABLE
DATA PRELOAD SINGLE
EXPORTS
;The names of the DLL functions
Summary
Factorial
在文件mymaths.cpp开头,声明了动态连接库所包含的两个函数:Summary和Factorial。接着是DllEntryPoint()函数的定义。DllEntryPoint()顾名思义是动态连接库的入口,应用程序通过该入口访问动态连接库提供的服务。DllEntryPoint()主体是一个switch/case语句:
switch(dwReason)
{
case DLL_PROCESS_ATTACH:
{
//一些初始化代码
break;
}
case DLL_PROCESS_DETACH:
{
//一些用于清理的代码
break;
}
}
其中,在case DLL_PROCESS_ATTACH分支可加入动态连接库执行时的一些初始化代码。在case DLL_PROCESS_DETACH加入动态连接库被卸载时的一些清理代码,比如释放动态连接库运行时申请的内存等。
在DllEntryPoint()函数后,是两个函数Summary和Factorial函数的定义。它们的定义与前面的静态库完全相同。在这里用户可以放入任何函数。
另外,我们还需要一个mymaths.def文件。这个文件记录了可被外部应用程序使用的DLL库函数名字。这些名字信息和对应的函数位置的信息将被编译进动态连接库文件中,然后应用程序根据函数名字和函数位置对照表来找到对应的函数。
按F7编译工程,Visual C++就在mymaths\debug目录下生成一个mymaths.dll动态连接库文件。
现在,我们来使用刚才生成的动态连接库。我们并不重新生成一个程序,而是修改前面测试静态库时的test程序。首先,把mymaths\debug目录下的mymaths.dll拷贝到test\debug目录下。test程序运行时,会在该目录下搜索动态连接库文件。然后修改testdlg.h,在其中加入一个函数LoadDLL()的声明,见清单9.4。LoadDLL用于载入动态连接库。
清单9.4 修改后的对话框头文件
class CTestDlg : public CDialog
{
// Construction
public:
CTestDlg(CWnd* pParent = NULL); // standard constructor
protected:
void LoadDLL();
//......
}
然后修改testdlg.cpp,修改后如清单9.5。
清单95. TestDlg.cpp文件
// TestDlg.cpp : implementation file
//
#include "stdafx.h"
#include "Test.h"
#include "TestDlg.h"
//#include "mymath.h" //注释掉mymath.h头文件
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
//The instance of the Mymaths.DLL library
HINSTANCE ghMathsDLL=NULL;
//declare the Summary() function from the Mymaths.DLL libray.
typedef int (*SUMMARY)(int);
SUMMARY Summary;
//declare the Factorial() function from
//the Mymaths.DLL library.
typedef int (*FACTORIAL)(int);
FACTORIAL Factorial;
/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About
class CAboutDlg : public CDialog
{
//...
};
//CAboutDlg的一些成员函数定义
//CTestDlg的一些成员函数定义
void CTestDlg::OnSum()
{
// TODO: Add your control notification handler code here
LoadDLL();
int nSum=Summary(10);
CString sResult;
sResult.Format("Sum(10)=%d",nSum);
AfxMessageBox(sResult);
}
void CTestDlg::OnFactorial()
{
// TODO: Add your control notification handler code here
LoadDLL();
int nFact=Factorial(10);
CString sResult;
sResult.Format("10!=%d",nFact);
AfxMessageBox(sResult);
}
void CTestDlg::LoadDLL()
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -