MFCDLL编程(图解)

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。

编译器

编译时

链接

应用程序(*.exe)

#include <xx.h>

……

fun();

……

fun() {

……

}

静态库(*.lib)

……

……

fun() {

……

}

操作系统

运行时

链接

应用程序(*.exe)

#include <xx.h>

……

fun();

……

fun() {

……

}

动态链接库(*.dll)

……

……

fun() {

……

}

使用静态库函数

使用动态链接库

图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应用程序使用;

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

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

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

8.1.4  导出函数的方法

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

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

l 使用__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导出(或导入)的。例如,当使用DECLARE_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  设置依赖项

为了使客户程序可以调用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的头文件的头部添加包含语句:

#include "..\ExtDll\Compute.h"

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

public:

CCompute *m_pComp;

void Comp(UINT nID);

最后的头文件为:(其中绿色为向导添加的,红色为手工添加的)

// ExtClientDlg.h : 头文件

//

#include "..\ExtDll\Compute.h"

#pragma once

// 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();

};

在客户对话框类的初始化对话框成员函数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);

}

}

8.2.7  编译运行

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

编译后,会在解决方案的Debug或Release目录中生成动态链接库文件ExtDll.dll和客户程序的可执行文件ExtClient.exe,以及DLL的导出文件ExtDll.exp和(静态连接)库文件ExtDll.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。

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();

在客户对话框类的初始化对话框成员函数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下DLL编程(图解)

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

  2. MFC下CSocket编程详解(转)

    原文转自 http://blog.csdn.net/yejiansnake/article/details/2175778 MFC下CSocket编程详解: 1. 常用的函数和注意事项(详细的函数接口 ...

  3. Delphi下DLL编程知识(转)

    一.  DLL和系统变量     在 System 单元声明的变量中,有几个对DLL编程有特殊影响.IsLibrary 可以检测代码是执行在应用程序中还是执行在DLL中,在应用程序中 IsLibrar ...

  4. MFC下的DLL编程学习

    1.DLL库与LIB库对比: 静态链接库Lib(Static Link Library),是在编译的链接阶段将库函数嵌入到应用程序的内部.如果系统中运行的多个应用程序都包含所用到的公共库函数,则必然造 ...

  5. VS2010下MFC的串口编程

    串口通信简介 一般来说,计算机都有一个或多个串行端口,这些串口提供了外部设备与PC进行数据传输和通信的通道,在CPU和外设之间充当解释器的角色.当字符数据从CPU发送给外设时,这些字符数据将被转换成串 ...

  6. [转]VS 2012环境下使用MFC进行OpenGL编程

    我就不黏贴复制了,直接给出原文链接:VS 2012环境下使用MFC进行OpenGL编程 其它好文链接: 1.OpenGL系列教程之十二:OpenGL Windows图形界面应用程序

  7. 深入Delphi下的DLL编程

    深入Delphi下的DLL编程 作者:岑心 引 言 相信有些计算机知识的朋友都应该听说过“DLL”.尤其是那些使用过windows操作系统的人,都应该有过多次重装系统的“悲惨”经历——无论再怎样小心, ...

  8. 【转】VS2010下MFC的串口编程

    串口通信简介 一般来说,计算机都有一个或多个串行端口,这些串口提供了外部设备与PC进行数据传输和通信的通道,在CPU和外设之间充当解释器的角色.当字符数据从CPU发送给外设时,这些字符数据将被转换成串 ...

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

    VC++动态链接库(DLL)编程深入浅出(zz) 1.概论 先来阐述一下DLL(Dynamic Linkable Library)的概念,你可以简单的把DLL看成一种仓库,它提供给你一些可以直接拿来用 ...

随机推荐

  1. Java多线程和死锁

    一 .多线程: 售票窗口简单实例: public class SaleTicket { public static class Sale implements Runnable{ ; // @Over ...

  2. ASP.NET的三层架构(DAL,BLL,UI)

    ASP.NET的三层架构(DAL,BLL,UI) BLL   是业务逻辑层   Business   Logic   Layer DAL   是数据访问层   Data   Access   Laye ...

  3. White space is required before the encoding pseudo attribute in the XML declaration.

    错误出现的位置: <?xml version="1.0"encoding="UTF-8"?> 正确方式: <?xml version=&quo ...

  4. iOS开发下架在AppStore中销售的app

    1.登陆开发者账号 2.选择itunes connect 选择我的app 3.选择要下架的app 4.价格与销售范围 5.销售范围 6.点击存储 //如果想要重新在AppStore中进行销售只需要选择 ...

  5. HDU 2544 最短路(初涉SPFA算法)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2544 Problem Description 在每年的校赛里,所有进入决赛的同学都会获得一件很漂亮的t ...

  6. ubuntu显卡驱动安装及设置

    转自: Ubuntu 14.04 Nvidia显卡驱动安装及设置   更换主板修复grub 引导后,无法从Nvidia进入系统(光标闪烁), 可能是显卡驱动出了问题. 1. 进入BIOS设置, 从集成 ...

  7. win2008阿里一键环境包mysql老是1067报错

    目前查看并不是染毒导致mysql无法启动,而是在mysql的配置文件中配置了log这个参数,这个参数语义不明确,请您将“--log”更改为general_log_file并添加一行“general_l ...

  8. Token验证失败的解决方法

    Token验证失败 微信 微信公众平台开发 Token校验失败 URL Token原文 http://www.cnblogs.com/txw1958/p/token-verify.html Token ...

  9. mybatis的insert返回主键

    <insert id="insert" useGeneratedKeys="true" keyProperty="id" parame ...

  10. hibernate 配置文件

    hibernate.cfg.xml </session-factory> //DAO类 package com.hanqi.dao; import org.hibernate.Sessio ...