mfc导出dll(一)
1、例子
以下内容来自Creating and consuming MFC DLLs for Beginners
1.1、创建用于导出dll的工程
1.1.1、创建项目
A. 选择文件->新建->项目。
B. 选择模板MFC DLL,名称填写为MyDll,如图1.1。
C. 选择使用共享MFC DLL的规则DLL,如图1.2。
1.1.2、添加要导出的类与函数
A. 类视图中,选中MyDll,右键->添加->类,选择C++ 类,如图1.3。
B. 类的名称为CMyClass,如图1.4。
C. 类视图中,选中CMyClass,右键->添加->函数。
D. 返回类型CString,函数名SayHello,参数CString strName,如图1.5。
E. 实现SayHello
// CMyClass.cpp
CString CMyClass::SayHello(CString strName)
{
return "Hello " + strName;
}
1.1.3、将类中的函数声明为要导出的类型
为CMyClass()、~CMyClass()、SayHello()添加__declspec(dllexport)
// CMyClass.h
class CMyClass
{
public:
__declspec(dllexport) CMyClass(void);
__declspec(dllexport) ~CMyClass(void);
__declspec(dllexport) CString SayHello(CString strName);
};
1.1.4、编译
选择Release模式,进行编译,得到MyDll.dll和MyDll.lib。
如果有错误,可以参考以下解决方案: 报错: **1 error C2678: 二进制“+”: 没有找到接受“const char [7]”类型的左操作数的运算符(或没有可接受的转换) f:\MyDll\MyDll\MyClass.cpp 14**。 解决: 选中**MyDll**,右键->**属性**->**配置属性**->**常规**->**字符集**->**使用多字节字符集**。1.2、创建调用dll的工程
1.2.1、创建项目
A. 选择文件->新建->项目。
B. 选择模板MFC 应用程序,名称填写为TestDLL,如图1.6。
C. 应用程序类型选择基于对话框,点击完成,如图1.7。
1.2.2、修改UI界面
A. 点击Static Text控件,在属性窗口中修改Caption的值为"Enter your name and click ok"。
B. 在工具箱窗口中,拖动一个Edit Control 控件到界面上,如图1.8。
1.2.3、给Edit Control关联一个变量
A. 选中Edit Control控件,右键->添加变量。
B. 变量类型填写CString,变量名为m_edit,类别为Value,如图1.9。
1.2.4、给Button绑定一个单击事件
A. 选中确定按钮,双击,自动创建新函数void CTestDLLDlg::OnBnClickedOk()
1.2.5、导入dll
A. 在工程目录下创建include文件夹和lib文件夹,如图1.10。
将MyClass.h复制到include文件下,将MyDll.lib复制到lib文件夹下
B. 切换解决方案配置为Release
C. 选中TestDLL,右键->属性->C/C++->常规->附加包含目录,添加../include,如图1.11。
D. 选中TestDLL,右键->属性->链接器->常规->附加库目录,添加../lib,如图1.12。
1.2.6、添加头文件和lib文件
// TestDLLDlg.h
#include "MyClass.h"
#pragma comment(lib, "MyDll.lib")
1.2.7、创建MyClass对象
在CTestDLLDlg类中添加CMyClass objMyClass
// TestDLLDlg.h
class CTestDLLDlg : public CDialog
{
// 构造
public:
CTestDLLDlg(CWnd* pParent = NULL); // 标准构造函数
CMyClass objMyClass;
1.2.8、实现确定单击事件OnBnClickedOk
// TestDLLDlg.cpp
void CTestDLLDlg::OnBnClickedOk()
{
// TODO: 在此添加控件通知处理程序代码
UpdateData(true);
CString strResult = objMyClass.SayHello(m_edit);
AfxMessageBox (strResult);
//OnOK();
}
1.3、编译运行
A. 选择Release模式,进行编译,得到TestDLL.exe。
如果有错误,可以参考以下解决方案: 报错: **1>TestDLLDlg.obj : error LNK2001: 无法解析的外部符号 "public: class ATL::CStringTB. 将MyDll.dll拷贝TestDLL.exe到同级目录下,单击TestDLL.exe运行,如图1.13。
2、知识点
2.1、MFC的dll工程
-
MFC编译dll在创建项目时已经提供了模板MFC DLL。
-
在MFC DLL模板中有共享MFC DLL的规则DLL 、带静态链接MFC的规则DLL和MFC扩展DLL三种。选择共享MFC DLL的规则DLL后,在运行该dll时,机器必须安装MFC库。选择带静态链接MFC的规则DLL,在运行该dll时不需要安装MFC库。
2.2、导出dll函数的两种方式
- 方法一:函数声明时标注_declspec(dllexport)表示导出函数
例如:
__declspec(dllexport) CString SayHello(CString strName);
- 方法二:.def文件中标注导出函数名
例如:
; DLL.def : 声明 DLL 的模块参数。
LIBRARY "DLL"
EXPORTS
; 此处可以是显式导出
SayHello
2.2、_declspec(dllexport)与.def文件的异同
-
对于VC++程序调用dll两者没有区别,对于其他(例如VB)程序调用dll最好用.def方式。
-
对于类的导出,往往使用_declspec(dllexport)方式
2.3、__declspec(dllexport)和__declspec(dllimport)的区别
该部分摘自[__declspec(dllexport) & __declspec(dllimport)](http://www.cnblogs.com/xd502djj/archive/2010/09/21/1832493.html)-
__declspec(dllexport)
声明一个导出函数,是说这个函数要从本DLL导出。我要给别人用。一般用于dll中。
省掉在DEF文件中手工定义导出哪些函数的一个方法。当然,如果你的DLL里全是C++的类的话,你无法在DEF里指定导出的函数,只能用__declspec(dllexport)导出类。 -
__declspec(dllimport)
声明一个导入函数,是说这个函数是从别的DLL导入。我要用。一般用于使用某个dll的exe中。
不使用 __declspec(dllimport) 也能正确编译代码,但使用 __declspec(dllimport) 使编译器可以生成更好的代码。编译器之所以能够生成更好的代码,是因为它可以确定函数是否存在于 DLL 中,这使得编译器可以生成跳过间接寻址级别的代码,而这些代码通常会出现在跨 DLL 边界的函数调用中。但是,必须使用 __declspec(dllimport) 才能导入 DLL 中使用的变量。
2.4、_declspec(dllexport)兼容C的通常使用方式
A. 宏定义__declspec(dllexport)
#ifdef TOOL_EXPORTS
#define TOOL_API extern "C" __declspec(dllexport)
#else
#define TOOL_API extern "C" __declspec(dllimport)
#endif
TOOL_API int Test(int a,int b);
B. 在工程中定义宏TOOL_EXPORTS
点击工程,右键属性->C/C++->预处理器->预处理器定义,添加TOOL_EXPORTS,如图2.1