前言
动态库dll与静态库lib编程4:MFC规则DLL教学。
一、说明
1.前面介绍的均为Win32DLL,即不利用MFC的DLL。
2.MFC规则DLL的特点:DLL内部可以利用MFC类库、可以被其他所有支持DLL技术的语言所调用(与Win32DLL一样)。
3.MFC规则DLL的入口点函数:默认情况下DLL的入口点函数都是DLLMain,MFC规则DLL也不破例,但是由于是支持MFC的,以是在MFC规则DLL中,DllMain函数已经被MFC所封装,以是在你的工程项目中是看不到DllMain函数的。就好像在MFC对话框工程中找不到WinMain函数是一样的,不外也有一些补救的技巧,就是InitInstance()和ExitInstance()函数,当进程初始化调用DLL时,DLL中会默认调用谁人InitInstance()函数(在这个函数中写一些构造和初始化代码),当.exe退出时DLL会调用ExitInstance()函数(在这个函数中写一些退出和析构的代码),但是当有新的线程时,出于步伐安全性思量则没有什么好的办法举行处理。
4.MFC规则DLL分为两类:1.静态链接到MFC的规则DLL,与MFC库静态链接,会将MFC类库的代码直接编译天生到DLL文件中,在调用这种DLL的接口时,MFC利用DLL的资源,因此不必要模块状态的切换。但是缺点就是利用这种方式天生的DLL文件巨细较大。2.动态链接到MFC的规则DLL:可以和调用DLL的.exe同时动态链接到MFC库,在这种情况下,MFC利用主应用步伐(即:.exe步伐)的资源句柄来加载资源模板,这样,当DLL和应用步伐中存在相同ID的资源时,就要举行模块的切换,以便MFC能够找到正确的资源模板。
二、详细实现
2.1新建项目
先新建项目,选择MFC动态链接库,工程项目名字自定义即可,这里取名为MFCDLL,点击确定
这里为了演示模块状态的切换,利用动态链接到MFC的规则DLL,选择利用共享MFC DLL的通例DLL,这里不利用网络编程,附加功能不选择即可。
新建工程项目成功,编译器自动为我们天生了部分头文件和源文件
打开MFCDLL.cpp源文件,如上所述并没有入口点函数DllMain(),可以将入口点函数视为InitInstance()函数
源文件MFCDLL.cpp中并没有发现ExitInstance()函数,打开类视图,选择CMFCDLLAPP,打开属性,选择图示小立方体按钮
可以在上图中看到已经列出了ExitInstance()函数,选择添加ExitInstance()函数
则MFCDLL.cpp中已经自动出现了ExitInstance()函数框架,可以把析构和卸载方面的代码写在ExitInstance()函数中
2.2 模块切换的演示
在资源视图中右键MFCDLL.rc,点击添加资源
新建一个对话框资源
此时即在DLL工程中加入了一个对话框模板,将标题设置为DLL Dialog,自定义即可
在解决方案资源管理器中再新建一个工程,用于天生一个.exe调用天生的DLL
选择MFC应用,设置名字为MFCDllCall
应用步伐范例选择对话框,其他默认即可,其他步骤都利用默认值,点击下一步,直到最后天生的类,点击完成
设置MFCDllCall项目为启动项目
同样在MFCDllCall项目中添加一个对话框模板
为了区分,将对话框的名字改为EXE Dialog
运行步伐,此时主对话框默以为下图
我们举行一些更改,删去下图中框起部分
然后添加两个按钮
Button1用来调用exe的Dialog模板,Button2用来调用exe的Dialog模板,并重命名两个按钮,Button1的Caption设为EXE Dialog,ID设为IDC_EXE_BTN;Button2的Caption设为DLL Dialog,ID设为IDC_DLL_BTN。目标为当点击EXE Dialog时弹出工程MFCDllCall的对话框模板;点击DLL Dialog时弹出工程MFCDLL的对话框模板。
下面添加两个按钮的响应函数。这部分为MFC消息映射机制内容,详细教学见https://blog.csdn.net/qq_59940419/article/details/144293369?spm=1001.2014.3001.5502,这里不再重复。
EXE Dialog按钮的响应函数如下,
- void CMFCDllcallDlg::OnBnClickedExeBtn() // EXE Dialog按钮的响应函数
- {
- // TODO: 在此添加控件通知处理程序代码
- CDialog dlg(IDD_DIALOG1); //定义一个变量 ,初始化为刚刚建立的对话框模板的ID(对应MFCDllCall项目的)
- dlg.DoModal(); // 对话框的弹出
- }
复制代码 由于DLL工程必要利用一个函数导出,来实现DLL工程中对话框模板的体现,因此必要先实现如下代码来举行函数导出,这部分代码在MFCDLL.cpp源文件中实现。放在函数ExitInstance()的实现框架后即可
- void ShowDLLDlg()
- {
- CDialog dlg(IDD_DIALOG1); //定义一个变量,初始化为刚刚建立的对话框模板的ID(对应MFCDLL项目的)
- dlg.DoModal(); // 对话框的弹出
- }
复制代码 然后利用提供的* .def文件举行函数的导出
- ; MFCDLL.def: 声明 DLL 的模块参数。
- LIBRARY "MFCDLL"
- EXPORTS
- ; 此处可以是显式导出
- ShowDLLDlg @1
复制代码 编译后可以看到函数ShowDLLDlg()被成功导出
接下来必要在MFCDllcall工程中调用该导出函数ShowDLLDlg(),在MFCDllcallDlg.cpp源文件中添加如下代码举行函数的调用,放在文件上方体系自动天生的宏定义后即可
- // 动态链接库导出函数的调用,利用隐式链接方法
- #pragma comment(lib, "..\\DeBug\\MFCDLL.lib")
- _declspec (dllimport) void ShowDLLDlg();
复制代码 然后调用函数ShowDLLDlg()
- void CMFCDllcallDlg::OnBnClickedDllBtn() // DLL Dialog按钮的响应函数
- {
- // TODO: 在此添加控件通知处理程序代码
- ShowDLLDlg();
- }
复制代码 打开MFCDllcall工程的Resource.h头文件,检察IDD_DIALOG1对应的数值定义为129(每个人可能不一样)
打开MFCDLL工程的Resource.h头文件,检察IDD_DIALOG1对应的数值定义为1000(每个人可能不一样)
将MFCDLL工程的Resource.h头文件中IDD_DIALOG1对应的数值也定义为和MFCDllcall工程一样的129。如果不举行更改点击DLL Dialog按钮是没有作用的,二者需保持一致。
这样就会出现一种错误征象,运行步伐,点击EXE Dialog按钮,弹出EXE Dialog对话框模板;
点击DLL Dialog按钮,希望弹出的是DLL Dialog对话框模板,但是也弹出EXE Dialog对话框模板,这就出现题目了
造成这种征象的原因是:动态链接到MFC的规则DLL默认情况下会利用主应用步伐(.exe)的资源句柄来加载资源模板。以是这里就利用MFCDllcall工程中的对话框模板。解决的办法是模块状态切换,即在实行MFCDLL工程内部代码的时间,必要调用该工程的内部资源;在实行MFCDllcall工程内部代码的时间,必要调用该工程的内部资源。
解决方法共有三种:
1.AFX_MANAGE_STATE(AfxGetStaticModuleState());放入函数ShowDLLDlg()的实现中
- void ShowDLLDlg()
- {
- AFX_MANAGE_STATE(AfxGetStaticModuleState()); // 将资源的主句柄转换到动态链接库当中,只要程序中加载资源,都在该程序所在工程中进行查找
- CDialog dlg(IDD_DIALOG1); //定义一个变量,初始化为刚刚建立的对话框模板的ID(对应MFCDLL项目的)
- dlg.DoModal(); // 对话框的弹出
- }
复制代码 此时点击DLL Dialog按钮弹出对话框正确,说明资源模块切换成功。
2. 意思和方法1是一样的,代码相对复杂
- HINSTANCE hSaveInst = AfxGetResourceHandle();
- AfxSetResourceHandle(theApp.m_hInstance);
- //...执行代码
- AfxSetResourceHandle(hSaveInst);
复制代码 此时的ShowDLLDlg()函数实现如下:
- void ShowDLLDlg()
- {
- // 方法1:
- //AFX_MANAGE_STATE(AfxGetStaticModuleState()); // 方法1:将资源的主句柄转换到动态链接库当中,只要程序中加载资源,都在该程序所在工程中进行查找。
- // 方法2:
- HINSTANCE hSaveInst = AfxGetResourceHandle();// 方法2:取得当前应用程序的实例句柄,保存到变量hSaveInst,此时实例句柄为.exe工程的
- AfxSetResourceHandle(theApp.m_hInstance);// 方法2:将当前的实例句柄设置为DLL的,之后实例句柄为DLL工程的
- CDialog dlg(IDD_DIALOG1); //定义一个变量,初始化为刚刚建立的对话框模板的ID(对应MFCDLL项目的)
- dlg.DoModal(); // 对话框的弹出
- AfxSetResourceHandle(hSaveInst);// 方法2:将实例句柄设置回来.exe的
- }
复制代码 3.前两种方法都是在MFCDLL工程中实现函数ShowDLLDlg()中举行,第三种方法不同,是在MFCDllcall工程,即.exe工程中举行修改。
先将方法1和方法2的代码注释掉
在MFCDllcallDlg.cpp源文件中找到调用函数ShowDLLDlg()部分
修改后变为如下代码:
- void CMFCDllcallDlg::OnBnClickedDllBtn() // DLL Dialog按钮的响应函数
- {
- // TODO: 在此添加控件通知处理程序代码
- // 资源模块切换方法3:
- HINSTANCE hExeInst = GetModuleHandle(NULL); //资源模块切换方法3: 取得指定模块的句柄,参数为模块的路径,返回传入路径文件的实例句柄,参数为NULL返回当前exe的实例句柄;NULL可换为_T("MFCDllcall.exe")
- HINSTANCE hDLLInst = GetModuleHandle(_T("MFCDLL.dll")); //资源模块切换方法3: 注意:该路径为与MFCDllcall.exe的相对路径
- ASSERT(hExeInst && hDLLInst); //资源模块切换方法3: 判断一下这两个句柄都不为空
- AfxSetResourceHandle(hDLLInst); //资源模块切换方法3: 资源搜索句柄设为动态链接库的
- ShowDLLDlg();
- AfxSetResourceHandle(hExeInst); // 资源模块切换方法3:将资源搜索句柄变回来.exe的
- }
复制代码 实际上,最方便的还是第一种方法,前两种方法是在DLL导出函数中添加,第三种方法是在.exe步伐中举行添加。
总结
动态库dll与静态库lib编程4:MFC规则DLL教学。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |