DLL(Dynamic Link Library,动态链接库)是微软公司为Windows和OS/2操作系统设计一种供应用程序在运行时调用的共享函数库。DLL是应用程序的一种扩展,也是软件共享和重用的传统方法。

DLL除了可同时被多个应用程序共享外,还可以在不改变调用接口(从而不需修改使用它的应用程序)的情况下,改进和升级里面的库函数。而且DLL与编写它的语言无关,例如,用VC生成的规则DLL,可以被VB、Delphi等生成的应用程序使用。

DLL可以用多种语言和工具编写,我们这里只介绍如何使用MFC来编写和使用DLL。相关说明文档位于MSDN帮助的“目录\开发工具和语言\Visual Studio\Visual C++\常见编程方法\DLL\”中。

8.1  基础

本节先讨论DLL与静态库的区别,然后列出几种适合放置DLL的目录,最后介绍MFC DLL的三种类型。

8.1.1  DLL与静态链接库

静态链接库Lib(Static Link Library),是在编译的链接阶段将库函数嵌入到应用程序的内部。如果系统中运行的多个应用程序都包含所用到的公共库函数,则必然造成很大的浪费。这样即增加了链接器的负担,也增大了可执行程序的大小,还加大了内存的消耗。Lib的好处是应用程序可以独立运行,而不需要在操作系统中另外安装对应的DLL。

而DLL采用动态链接,对公用的库函数,系统只有一个拷贝(一般是位于系统目录的*.DLL文件),而且只有在应用程序真正调用时,才加载到内存。在内存中的库函数,也只有一个拷贝,可供所有运行的程序调用。当再也没有程序需要调用它时,系统会自动将其卸载,并释放其所占用的内存空间。参见图8-1。

DLL的缺点是应用程序不能独立运行,需要在操作系统中另外安装对应的DLL。例如,如果你的MFC项目被设置成“在共享DLL中使用MFC”的,则虽然生成的可执行程序很小,但是在其他没有安装Visual C++(运行环境)的机器上是不能直接运行的,需要另外安装MFC的动态链接库(如mfc90.dll)。

8.1.2  放置DLL的目录

为了使需要动态链接库的应用程序可以运行,需要将DLL文件放在操作系统能够找到的地方。Windows操作系统查找DLL的目录顺序为:

  1. 所在目录——当前进程的可执行模块所在的目录,即应用程序的可执行文件(*.exe)所在的目录。
  2. 当前目录——进程的当前目录。
  3. 系统目录——Windows操作系统安装目录的系统子目录,如C:\Windows\ System32。可用GetSystemDirectory函数检索此目录的路径。
  4. Windows目录——Windows操作系统安装目录,如C:\Windows\。可用GetWindowsDirectory函数检索此目录的路径。
  5. 搜索目录——PATH环境变量中所包含的自动搜索路径目录,一般包含C:\Windows\和C:\Windows\System32\等目录。可在命令行用Path命令来查看和设置,也可以通过(在“我的电脑”右键菜单中选“属性”菜单项)“系统属性”中的环境变量,来查看或编辑“Path”系统变量和“PATH”用户变量。

8.1.3  MFC DLL的类型

使用MFC编写的DLL,可以分成两大类:

l规则DLL——规则(regular)DLL中所包含的函数,可以被所有Windows应用程序使用;

共享MFC——DLL中不包含MFC库函数,需要另外安装MFC动态链接库后才能使用;

静态MFC——DLL中包含MFC库函数,可以脱离MFC动态链接库独立使用。

扩展DLL——扩展(extension)DLL中所定义的类和函数,只能被所MFC应用程序使用。而且扩展DLL中不能包含MFC库函数,也需要另外安装MFC动态链接库后才能使用。

8.1.4  导出函数的方法

使用MFC创建DLL时,从项目中导出(export)函数到DLL文件的方法有:

使用模块定义文件(.def)。

使用__declspec(dllexport)关键字或其替代宏AFX_EXT_CLASS。

这两种方法是互斥的,对每个函数只需用一种方法即可。另外,DEF文件只能用来导出函数,不能用于导出整个类。导出C++类,必须用__declspec(dllexport)关键字或其替代宏AFX_EXT_CLASS。

1.DEF文件

模块定义(module definition)文件(.def)是包含一个或多个描述DLL各种属性的模块语句的文本文件。DEF文件必须至少包含下列模块定义语句:

l 文件中的第一个语句必须是LIBRARY语句。此语句将.def文件标识为属于DLL。LIBRARY语句的后面是DLL的名称(缺省为DLL项目名)。链接器将此名称放到DLL的导入库中。

l EXPORTS语句列出名称,可能的话还会列出DLL导出函数的序号值。通过在函数名的后面加上@符和一个数字,给函数分配序号值。当指定序号值时,序号值的范围必须是从1到N,其中N是DLL导出函数的个数。

即,DEF文件的格式为:(在这两个语句之间,还可以加上可选的描述语句:DESCRIPTION "库描述串"。分号;后的文本内容行为注释)

; 库名.def

LIBRARY 库名

EXPORTS

函数名1 @1

函数名2 @2

……

函数名n @n

在使用MFC DLL向导创建MFC DLL项目时,VC会自动创建一个与项目同名但没有任何函数导出项的DEF文件(项目名.def),格式为:

; 项目名.def : 声明 DLL 的模块参数。

LIBRARY      "项目名"

EXPORTS

; 此处可以是显式导出

例如,项目名为RegDll的DEF文件(RegDll.def)的内容为:

; RegDll.def : 声明 DLL 的模块参数。

LIBRARY      "RegDll"

EXPORTS

; 此处可以是显式导出

如果生成扩展DLL并使用.def文件导出,则将下列代码放在包含导出类的头文件的开头和结尾:

#undef AFX_DATA

#define AFX_DATA AFX_EXT_DATA

// <你的头文件体>

#undef AFX_DATA

#define AFX_DATA

这些代码行确保内部使用的MFC变量或添加到类的变量是从扩展DLL导出(或导入)的。例如,当使用DLAECRE_DYNAMIC派生类时,该宏扩展以将CRuntimeClass成员变量添加到类。省去这四行代码可能会导致不能正确编译或链接DLL,或在客户端应用程序链接到DLL时导致错误。

当生成DLL时,链接器使用.def文件创建导出(.exp)文件和导入库(.lib)文件。然后,链接器使用导出文件生成DLL文件。隐式链接到DLL的可执行文件在生成时链接到导入库。请注意,MFC本身就是使用.def文件从MFCx0.dll导出函数和类的。

2.关键字或宏

除了使用DEF文件来导出函数外,还可以在源程序中使用__declspec(dllexport)关键字或其替代宏AFX_EXT_CLASS:

#define AFX_EXT_CLASS  AFX_CLASS_EXPORT (定义在头文件afxv_dll.h中)

#define AFX_CLASS_EXPORT  __declspec(dllexport) (定义在头文件afxver_.h中)

来导出函数和整个C++类。

具体的格式为:

l导出整个类:

class AFX_EXT_CLASS 类名[ : public基类]

{

……

}

l 导出类的成员函数:

class 类名[ : public基类]

{

AFX_EXT_CLASS 返回类型 函数名1(……) ;

AFX_EXT_CLASS 返回类型 函数名2(……) ;

……

}

l 导出外部C格式的(全局)函数:

extern "C" __declspec(dllexport) 返回类型 函数名(……)

{

……

}

如果希望用MFC(C++)编写的规则DLL中的函数,也能够被非MFC程序来调用,需要为函数声明指定extern "C"。不然,C++编译器会使用C++类型安全命名约定(也称作名称修饰)和C++调用约定(使用此调用约定从C调用会很困难)。

为了使用方便,可以定义宏:

#define DllExport extern "C" __declspec(dllexport)

然后再使用它,例如:

DllExport int Add(int d1, int d2) {……}

8.2  扩展DLL

使用MFC编写的扩展DLL,可以导出整个类(从而能使用类中的所有成员,包括数据成员和成员函数),也可以导出指定的若干(成员或全局)函数。

下面我们通过一个四则运算的例子,看看如何用宏AFX_EXT_CLASS来编写和使用导出整个C++类的扩展MFC DLL。

8.2.1  创建DLL项目

我们创建一个名为ExtDll的扩展DLL的“Visual C++”之“MFC”的“MFC DLL”项目,注意需选中“创建解决方案的目录”复选框,参见图8-2。

图8-2  新建MFC DLL项目ExtDll的对话框

按“确定”钮,弹出“MFC DLL向导”对话框。在“DLL类型”栏中,选中“扩展DLL”单选钮,参见图8-3。按“完成”钮,创建ExtDll解决方案和项目。

图8-3  选择“扩展DLL”的MFC DLL向导对话框

8.2.2  添加导出类

为新项目添加用于四则计算的导出类CCompute。方法有多种,可以在项目管理区的“类视图”页中,选中项目名“ExtDll”,按鼠标右键,在弹出菜单中选“添加\类”。在弹出的“添加类”对话框中,选择“Visual C++”之“MFC”的“MFC类”项,参见图8-4。

图8-4  添加类对话框

按“添加”钮,弹出“MFC类向导”对话框。在“类名”栏中键入“CCompute”,在“基类”下拉式列表,选“CObject”,参见图8-5。按“完成”钮,添加该类到ExtDll项目。

图8-5  MFC类向导对话框

8.2.3  编写导出类代码

我们将整个CCompute类设为导出类,并在里面添加2个成员变量、1个构造函数和4个用于四则运算的成员函数,外加1个演示导出函数的取模全局函数Mod。

下面是CCompute类的头文件(Compute.h),其中红色的部分是自己添加:(注意导出宏AFX_EXT_CLASS的使用)

#pragma once// CCompute 命令目标class AFX_EXT_CLASS CCompute : public CObject{public:int m_data1, m_data2;public:CCompute();CCompute(int d1, int d2);virtual ~CCompute();public:int Add();int Sub();int Mul();double Div();};AFX_EXT_CLASS int Mod(int d1, int d2);

下面是CCompute类的代码源文件(Compute.cpp),其中红色为自己添加的部分:

// Compute.cpp : 实现文件//
#include "stdafx.h"#include "Compute.h"// CCompute
CCompute::CCompute(){}CCompute::CCompute(int d1, int d2){m_data1 = d1;m_data2 = d2;}CCompute::~CCompute(){}// CCompute 成员函数int CCompute::Add(){return m_data1 + m_data2;}int CCompute::Sub(){return m_data1 - m_data2;}int CCompute::Mul(){return m_data1 * m_data2;}double CCompute::Div(){if (m_data2 == 0 ) {AfxMessageBox(L"Divided by zero!");return 0;}return (double)m_data1 / m_data2;}int Mod(int d1, int d2){if (d2 == 0 ) {AfxMessageBox(L"Modulo by zero!");return 0;}return d1 % d2;}

编译运行时,后弹出图8-6所示的对话框:

图8-6  调试会话的可执行文件对话框

要求你选择或输入使用此DLL的应用程序之可执行文件的名称或路径。这是因为DLL虽然包含了可运行函数的二进制代码,但是它并不是独立的应用程序,不能单独运行。因此,我们必须编写使用DLL的客户程序。

8.2.4  添加客户程序项目

为了演示扩展DLL的应用,我们在原解决方案ExtDll中,添加一个客户程序项目ExtClient。具体做法是,打开新建项目对话框,选中“Visual C++”之“MFC”的“MFC应用程序”模板,键入项目名ExtClient。注意,需选在对话框底部的“解决方案”下拉式列表中选中“添入解决方案”表项,参见图8-7。

图8-6  新建客户程序项目的对话框

按“确定”钮进入“MFC应用程序向导”对话框,在“应用程序类型”页,选中“基于对话框”单选钮,按“完成”添加项目。

此时,ExtDll解决方案包含两个项目:DLL项目ExtDll和客户程序项目ExtClient,生成的文件目录结构为:

ExtDll ←解决方案目录

Debug ←解决方案的调试目录

Release ←解决方案的发行目录

ExtDll ←DLL项目目录

Debug ←DLL的调试目录

Release ←DLL的发行目录

res ←DLL的资源目录

ExtClient ←客户程序项目目录

Debug ←客户程序的调试目录

Release ←客户程序的发行目录

res ←客户程序的资源目录

8.2.5  设置依赖项(个人看还要添加引用ExtDll)

为了使客户程序可以调用DLL,需要将它们关联起来。最简单的办法是设置DLL项目为客户项目的依赖项。具体做法是,在项目管理区中选中客户项目名“ExtClient”,选中菜单项“项目\项目依赖项”,在弹出的“项目依赖项”对话框中,选中“依赖栏”中的“ExtDll”复选框,参见图8-7。

图8-7  设置ExtClient项目依赖项的对话框

8.2.6  编写客户程序代码

1.编辑对话框资源

添加表示操作数的2个静态文本框和2个文本编辑框(ID值分别为IDC_DATA1和IDC_DATA2)、5个表示四则运算和取模运算的按钮(ID值分别为IDC_ADD、IDC_SUB、IDC_MUL、IDC_DIV和IDC_MOD)、表示计算结果的1个静态文本框和1个文本编辑框(ID值为IDC_RESULT),删除原来“确定”按钮,将原来的“取消”按钮的“Caption”属性值改为“退出”,参见图8-8。

图8-8  客户程序的对话框界面

2.添加控件变量

为了动态获取用户输入的数据,我们需要为2个表示操作数据的文本编辑框,添加控件的Value值类别int型变量m_iData1和m_iData2。

3.添加事件处理

分别对5个计算按钮,为对话框类CExtClientDlg添加按钮通知消息BN_CLICKED(鼠标单击)事件的处理程序OnBnClickedAdd等。

4.编写代码

为了让客户程序可以使用DLL项目中的计算类CCompute,需要在客户程序对话框类CExtClientDlg的头文件

在ExtClientDlg.h 中

添加  #include "..\ExtDll\Compute.h"//相对路径(这个比绝对路径要好),看情况..\表示相对自己上一级目录。用来引入CCompute类。

检查class CAboutDlg : public CDialogEx 中的,对话框数据enum { IDD = 操作对话框数据ID };

在对话框类的定义中,手工添加公共型类变量和成员函数:

public:   CCompute *m_pComp;    void Comp(UINT nID);

ExtClientDlg.c //文件

// CExtClientDlg 对话框class CExtClientDlg : public CDialog{……public:int m_iData1;int m_iData2;CCompute *m_pComp;void Comp(UINT nID);afx_msg void OnBnClickedAdd();afx_msg void OnBnClickedSub();afx_msg void OnBnClickedMul();afx_msg void OnBnClickedDiv();afx_msg void OnBnClickedMod(); };
在客户对话框类ExtClientDlg.cpp的初始化对话框成员函数OnInitDialog中,手工添加设置数据编辑框初值的代码(红色部分):
BOOL CExtClientDlg::OnInitDialog(){CDialog::OnInitDialog();……// TODO: 在此添加额外的初始化代码

SetDlgItemInt(IDC_DATA1, 5);SetDlgItemInt(IDC_DATA2, 3);return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE

}
 

代码文件ExtClientDlg.cpp中其他新加内容有:(其中红色部分为手工添加的)

void CExtClientDlg::OnBnClickedAdd(){// TODO: 在此添加控件通知处理程序代码

Comp(IDC_ADD);}void CExtClientDlg::OnBnClickedSub(){// TODO: 在此添加控件通知处理程序代码

Comp(IDC_SUB);

}void CExtClientDlg::OnBnClickedMul(){// TODO: 在此添加控件通知处理程序代码

Comp(IDC_MUL);}void CExtClientDlg::OnBnClickedDiv(){// TODO: 在此添加控件通知处理程序代码

Comp(IDC_DIV);}
void CExtClientDlg::OnBnClickedMod(){// TODO: 在此添加控件通知处理程序代码

Comp(IDC_MOD);}void CExtClientDlg::Comp(UINT nID){UpdateData(); // 动态获取用户输入的数据并赋值给对应的控件变量m_pComp = new CCompute(m_iData1, m_iData2); // 创建计算对象int r;double dr;switch(nID) { // 进行四则和取模运算case IDC_ADD: r = m_pComp->Add(); break;case IDC_SUB: r = m_pComp->Sub(); break;case IDC_MUL: r = m_pComp->Mul(); break;case IDC_DIV: dr = m_pComp->Div(); break;case IDC_MOD: r = Mod(m_iData1, m_iData2); break;}delete m_pComp;if (nID != IDC_DIV) SetDlgItemInt(IDC_RESULT, r); // 显示整数结果else { // 显示除法所得的实数结果wchar_t buf[20];swprintf_s(buf, 20, L"%g", dr);SetDlgItemText(IDC_RESULT, buf);}}//修改点击退出按钮动作----退出void CExtClientDlg::OnBnClickedCancel(){// TODO:在此添加控件通知处理程序代码
 exit(0); }

8.2.7  编译运行

为了运行客户程序,需要将客户程序项目设置成启动项目。具体做法是,先在项目管理区中选中ExtClient项目,然后选择菜单项“项目\设为启动项目”。

编译后,会在解决方案的Debug或Release目录中生成动态链接库文件ExtDll.dll和客户程序的可执行文件ExtClient.exe,以及DLL的导出文件ExtDll.exp和(静态连接)库文件ExtDll.lib。如果出现:

>ExtClientDlg.obj : error LNK2019: 无法解析的外部符号 "__declspec(dllimport) public: __thiscall CCompute::CCompute(int,int)" (__imp_??0CCompute@@QAE@HH@Z),该符号在函数 "public: void __thiscall CExtClientDlg::Comp(unsigned int)" (?Comp@CExtClientDlg@@QAEXI@Z) 中被引用

1>ExtClientDlg.obj : error LNK2019: 无法解析的外部符号 "__declspec(dllimport) public: virtual __thiscall CCompute::~CCompute(void)" (__imp_??1CCompute@@UAE@XZ),该符号在函数 "public: virtual void * __thiscall CCompute::`scalar deleting destructor'(unsigned int)" (??_GCCompute@@UAEPAXI@Z) 中被引用

1>D:\ExtDll\Debug\ExtClient.exe : fatal error LNK1120: 7 个无法解析的外部命令

这样的错误是因为缺少lib库导致添加操作如下,这里是缺少

右键“ExtClient”项目名称出现

下一步添加lib库

添加路径:

问题解决。

运行结果如图8-9所示:

图8-9  客户程序ExtClient的运行结果

8.3  规则DLL

使用MFC编写的规则DLL,虽然只能导出函数而不能导出整个类,但是其导出的函数却可以其他被非MFC应用程序所调用。下面我们仍通过上面的四则运算的例子,看看如何用关键字__declspec(dllexport)和extern "C"来编写和使用导出若干(全局)C函数的规则MFC DLL。

8.3.1  创建DLL项目

我们创建一个名为RegDll的规则DLL的“Visual C++”之“MFC”的“MFC DLL”项目,注意仍需选中“创建解决方案的目录”复选框,参见图8-10。

图8-10  新建MFC DLL项目RegDll的对话框

按“确定”钮,弹出“MFC DLL向导”对话框。在“DLL类型”栏中,选中“使用共享MFC DLL的规则DLL”单选钮,参见图8-11。按“完成”钮,创建RegDll解决方案和项目。

图8-11  选择规则DLL的MFC DLL向导对话框

也可以选择“带静态链接MFC的规则DLL”,差别是所生成的DLL中会包含MFC库,当然所生成的库文件也会大一些(但因此可不用另外安装MFC动态链接库)。例如,在此例中,选共享MFC所生成的RegDll.dll文件只有13KB大,而选择静态MFC的则有199KB。

规则DLL项目是使用共享MFC还是使用静态MFC,也可以在生成DLL项目之后,通过项目属性对话框的“配置属性\常规”页中的“MFC的使用”栏中的下拉式列表选项来切换,这一点与普通MFC应用程序项目的类似。

8.3.2  使用DEF文件导出函数

1.编辑DEF文件

在项目管理区中,选择“解决方案资源管理器”页,展开“RegDll”项目项,双击其“RegDll.def”子项,打开DLL项目中自动生成的DEF文件。在该DEF文件中加入需要导出的5个函数项:(红色部分为手工添加的)

; RegDll.def : 声明 DLL 的模块参数。

LIBRARY      "RegDll"

EXPORTS

; 此处可以是显式导出

Add @1

Sub @2

Mul @3

Div @4

Mod @5

2.编写导出函数代码

可以在RegDll项目的应用程序类的代码文件RegDll.cpp的尾部手工添加如下代码:

extern "C" int Add(int d1, int d2) { return d1 + d2;}extern "C" int Sub(int d1, int d2) { return d1 - d2;}extern "C" int Mul(int d1, int d2) { return d1 * d2;}extern "C" double Div(int d1, int d2) {if (d2 == 0) {AfxMessageBox(L"Divided by zero!");return 0;}return (double)d1 / d2;}extern "C" int Mod(int d1, int d2) {return d1 % d2;}

注意,函数前的extern "C"是不可少的,它指定按C语言约定来生成导出函数。不然,缺省情况下,C++编译器会生成冗长的函数修饰符,不能简单地用函数名来调用。

8.3.3  使用关键字__declspec(dllexport)导出函数

也可以不修改DEF文件,而在代码文件中直接用关键字__declspec(dllexport)和extern "C"来指定导出函数。对应的代码为:(也加在RegDll.cpp的尾部)

#define DllExport extern "C" __declspec(dllexport)DllExport int Add(int d1, int d2) { return d1 + d2;}DllExport int Sub(int d1, int d2) { return d1 - d2;}DllExport int Mul(int d1, int d2) { return d1 * d2;}DllExport double Div(int d1, int d2) {if (d2 == 0) {AfxMessageBox(L"Divided by zero!");return 0;}return (double)d1 / d2;}DllExport int Mod(int d1, int d2) {if (d2 == 0) {AfxMessageBox(L"Modulo by zero!");return 0;}return d1 % d2;}

8.3.4  编写客户程序

1.添加客户程序项目

与上节类似,为例演示DLL的调用,我们也为RegDLL解决方案添加一个客户程序——基于对话框的MFC应用程序项目RegClient,参见图8-12。

图8-12  添加客户程序项目RegClient的对话框

2.设置依赖项

我们也通过设置DLL项目为客户项目的依赖项将RegClient与RegDll.dll关联起来,参见图8-13。

图8-13  设置RegClient项目依赖项的对话框

3.编辑对话框资源

为了节省时间,避免重复劳动,可以复制ExtClient项目中的对话框。具体做法是:在RegDll解决方案环境中打开ExtDll解决方案中ExtClient项目的资源文件ExtClient.rc文件,(用鼠标或按Ctrl + A组合键)选中其主对话框中的所有控件,(按Ctrl + C或Ctrl + Insert组合键)复制它们到剪接板。然后打开RegClient项目的主对话框编辑器,先删除其中的所有控件,然后再粘贴剪接板中的控件到对话框,参见图8-8。具体操作如下:

打开ExtClient.rc文件

如下图

选择主对话框:

复制粘贴

4.编写代码

类似ExtClient程序,我们也需要为2个数据编辑框添加类变量,并逐个为运算符按钮添加单击事件处理函数。在头文件RegClientDlg.h的尾部会出现如下代码:(其中红色的Comp函数原型是手工添加的)

public:int m_iData1;int m_iData2;void Comp(UINT nID);afx_msg void OnBnClickedAdd();afx_msg void OnBnClickedSub();afx_msg void OnBnClickedMul();afx_msg void OnBnClickedDiv();afx_msg void OnBnClickedMod();

在客户对话框类RegClientDlg.cpp的初始化对话框成员函数OnInitDialog中,手工添加设置数据编辑框初值的代码(红色部分):

BOOL CRegClientDlg::OnInitDialog(){CDialog::OnInitDialog();……// TODO: 在此添加额外的初始化代码

SetDlgItemInt(IDC_DATA1, 5);SetDlgItemInt(IDC_DATA2, 3);return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE

}对应的代码文件RegClientDlg.cpp尾部新增的代码为:(其中红色部分是手工添加的)void CRegClientDlg::OnBnClickedAdd(){// TODO: 在此添加控件通知处理程序代码

Comp(IDC_ADD);}void CRegClientDlg::OnBnClickedSub(){// TODO: 在此添加控件通知处理程序代码

Comp(IDC_SUB);}void CRegClientDlg::OnBnClickedMul(){// TODO: 在此添加控件通知处理程序代码

Comp(IDC_MUL);}void CRegClientDlg::OnBnClickedDiv(){// TODO: 在此添加控件通知处理程序代码

Comp(IDC_DIV);}void CRegClientDlg::OnBnClickedMod(){// TODO: 在此添加控件通知处理程序代码

Comp(IDC_MOD);}#define DllImport extern "C" _declspec(dllimport)DllImport int Add(int d1, int d2);DllImport int Sub(int d1, int d2);DllImport int Mul(int d1, int d2);DllImport double Div(int d1, int d2);DllImport int Mod(int d1, int d2);void CRegClientDlg::Comp(UINT nID){UpdateData();int r;double dr;switch(nID) {case IDC_ADD: r = Add(m_iData1, m_iData2); break;case IDC_SUB: r = Sub(m_iData1, m_iData2); break;case IDC_MUL: r = Mul(m_iData1, m_iData2); break;case IDC_MOD: r = Mod(m_iData1, m_iData2); break;case IDC_DIV: dr = Div(m_iData1, m_iData2); break;}if (nID != IDC_DIV) SetDlgItemInt(IDC_RESULT, r);else {wchar_t buf[20];swprintf_s(buf, 20, L"%g", dr);SetDlgItemText(IDC_RESULT, buf);}}

5.编译运行

似上节的ExtClient项目,先设置RegClient项目为启动项目,再编译运行,结果如图8-14所示:

图8-14  客户程序RegClient的运行结果

MFC下DLL编程(图解)相关推荐

  1. MFC下CSocket编程详解

    MFC下CSocket编程详解:  1. 常用的函数和注意事项(详细的函数接口说明请查看MSDN): CSocket::Create 初始化(一般写服务器程序都不要用为好,用下面的 CSocket:: ...

  2. VC++动态链接库(DLL)编程(四)――MFC扩展 DLL

    VC++动态链接库(DLL)编程(四) ――MFC扩展 DLL 作者:宋宝华  e-mail:21cnbao@21cn.com   前文我们对非MFC DLL和MFC规则DLL进行了介绍,现在开始详细 ...

  3. VC++动态链接库(DLL)编程(三)――MFC规则DLL

    VC++动态链接库(DLL)编程(三) ――MFC规则DLL 作者:宋宝华  e-mail:21cnbao@21cn.com 第4节我们对非MFC DLL进行了介绍,这一节将详细地讲述MFC规则DLL ...

  4. Win32环境下动态链接库(DLL)编程原理

    Win32环境下动态链接库(DLL)编程原理 比较大应用程序都由很多模块组成,这些模块分别完成相对独立的功能,它们彼此协作来完成整个软件系统的工作.其中可能存在一些模块的功能较为通用,在构造其它软件系 ...

  5. VC++动态链接库(DLL)编程(二)--非MFC DLL

    4.非MFC DLL 4.1一个简单的DLL 第2节给出了以静态链接库方式提供add函数接口的方法,接下来我们来看看怎样用动态链接库实现一个同样功能的add函数. 如图6,在VC++中new一个Win ...

  6. VC++动态链接库(DLL)编程(一)――理解库

    VC++动态链接库(DLL)编程(一) ――理解库 作者:宋宝华  e-mail:21cnbao@21cn.com 1.概论 先来阐述一下DLL(Dynamic Linkable Library)的概 ...

  7. 如何调用DLL (基于Visual C++6.0的DLL编程实现)

    如何调用DLL (基于Visual C++6.0的DLL编程实现) http://www.programfan.com/article/showarticle.asp?id=2923 一.前言 自从微 ...

  8. VC++动态链接库(DLL)编程深入浅出(zz)

    1.概论 先来阐述一下DLL(Dynamic Linkable Library)的概念,你可以简单的把DLL看成一种仓库,它提供给你一些可以直接拿来用的变量.函数或类.在仓库的发展史上经历了" ...

  9. [转]C++学习:VC++动态链接库(DLL)编程深入浅出(zz)

    转自:http://www.cnblogs.com/chio/archive/2007/11/03/948480.html 1.概论 先来阐述一下DLL(Dynamic Linkable Librar ...

最新文章

  1. 【软考-软件设计师】计算机系统硬件基本组成
  2. 花木兰到底好看不,我用Python爬取了几万条评论!
  3. eclipse/myeclipse高亮显示相同变量名 .
  4. 计算机视觉-自定义对象检测器
  5. “约见”面试官系列之常见面试题之第七十八篇之fetch(建议收藏)
  6. 思科isis路由的优先级_【分享】超全!集成ISIS知识详解~
  7. 《从Excel到R 数据分析进阶指南》一2.6 查看数据表数值
  8. 解决谷歌自带翻译不出现问题
  9. flashpaper java_FlashPaper API 说明
  10. 四六级分数竟是这样算出来的!交白卷都不会得零分 (转)
  11. C# 定时关机小应用
  12. MATLAB符号积分范例
  13. GAPIT 3.0:全基因组关联分析与预测软件最新版发布
  14. centos7安装gparted分区工具及简单操作
  15. ios录制屏幕_如何使您的ios应用免受屏幕截图和录制的影响
  16. 会员积分体系付费会员的运营优化方法
  17. 远程连接mscs下oracle,oracle10G_windows_MSCS_双机安装
  18. 95后阿里P7晒出工资单:狠补了这个,真香....
  19. 靳氏DIV布局兼容“武林秘诀”
  20. 上海大学计算机考研专业群,19考研|2019考研专业、院校交流群,请对号入座!...

热门文章

  1. boost:is_straight_line_drawing用法的测试程序
  2. boost::detail模块实现二分法查找的测试程序
  3. ITK:来自图像的多分辨率金字塔
  4. ITK:在图像中线性插值位置
  5. DCMTK:DcmAttributeFilter类的测试程序
  6. VTK:PolyData之IsoLines
  7. C++实现skip list跳表(附完整源码)
  8. C++前缀++/–比后缀++/–的效率高
  9. QT的QQmlScriptString类的使用
  10. QT的QQmlExpression类的使用