图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。