动态库dll与静态库lib编程4:MFC规则DLL教学

打印 上一主题 下一主题

主题 1043|帖子 1043|积分 3129


前言

动态库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按钮的响应函数如下,
  1. void CMFCDllcallDlg::OnBnClickedExeBtn() // EXE Dialog按钮的响应函数
  2. {
  3.         // TODO: 在此添加控件通知处理程序代码
  4.         CDialog dlg(IDD_DIALOG1); //定义一个变量 ,初始化为刚刚建立的对话框模板的ID(对应MFCDllCall项目的)
  5.         dlg.DoModal(); // 对话框的弹出
  6. }
复制代码
由于DLL工程必要利用一个函数导出,来实现DLL工程中对话框模板的体现,因此必要先实现如下代码来举行函数导出,这部分代码在MFCDLL.cpp源文件中实现。放在函数ExitInstance()的实现框架后即可
  1. void ShowDLLDlg()
  2. {
  3.         CDialog dlg(IDD_DIALOG1); //定义一个变量,初始化为刚刚建立的对话框模板的ID(对应MFCDLL项目的)
  4.         dlg.DoModal(); // 对话框的弹出
  5. }
复制代码
然后利用提供的* .def文件举行函数的导出
  1. ; MFCDLL.def: 声明 DLL 的模块参数。
  2. LIBRARY "MFCDLL"
  3. EXPORTS
  4.     ; 此处可以是显式导出
  5.         ShowDLLDlg @1
复制代码
编译后可以看到函数ShowDLLDlg()被成功导出

接下来必要在MFCDllcall工程中调用该导出函数ShowDLLDlg(),在MFCDllcallDlg.cpp源文件中添加如下代码举行函数的调用,放在文件上方体系自动天生的宏定义后即可
  1. // 动态链接库导出函数的调用,利用隐式链接方法
  2. #pragma comment(lib, "..\\DeBug\\MFCDLL.lib")
  3. _declspec (dllimport) void ShowDLLDlg();
复制代码
然后调用函数ShowDLLDlg()
  1. void CMFCDllcallDlg::OnBnClickedDllBtn() // DLL Dialog按钮的响应函数
  2. {
  3.         // TODO: 在此添加控件通知处理程序代码
  4.         ShowDLLDlg();
  5. }
复制代码
打开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()的实现中
  1. void ShowDLLDlg()
  2. {
  3.         AFX_MANAGE_STATE(AfxGetStaticModuleState()); // 将资源的主句柄转换到动态链接库当中,只要程序中加载资源,都在该程序所在工程中进行查找
  4.         CDialog dlg(IDD_DIALOG1); //定义一个变量,初始化为刚刚建立的对话框模板的ID(对应MFCDLL项目的)
  5.         dlg.DoModal(); // 对话框的弹出
  6. }
复制代码
此时点击DLL Dialog按钮弹出对话框正确,说明资源模块切换成功。

2. 意思和方法1是一样的,代码相对复杂
  1. HINSTANCE hSaveInst = AfxGetResourceHandle();
  2. AfxSetResourceHandle(theApp.m_hInstance);
  3. //...执行代码
  4. AfxSetResourceHandle(hSaveInst);
复制代码
此时的ShowDLLDlg()函数实现如下:
  1. void ShowDLLDlg()
  2. {
  3.         // 方法1:
  4.         //AFX_MANAGE_STATE(AfxGetStaticModuleState()); // 方法1:将资源的主句柄转换到动态链接库当中,只要程序中加载资源,都在该程序所在工程中进行查找。
  5.         // 方法2:
  6.         HINSTANCE hSaveInst = AfxGetResourceHandle();// 方法2:取得当前应用程序的实例句柄,保存到变量hSaveInst,此时实例句柄为.exe工程的
  7.         AfxSetResourceHandle(theApp.m_hInstance);// 方法2:将当前的实例句柄设置为DLL的,之后实例句柄为DLL工程的
  8.         CDialog dlg(IDD_DIALOG1); //定义一个变量,初始化为刚刚建立的对话框模板的ID(对应MFCDLL项目的)
  9.         dlg.DoModal(); // 对话框的弹出
  10.         AfxSetResourceHandle(hSaveInst);// 方法2:将实例句柄设置回来.exe的
  11. }
复制代码
3.前两种方法都是在MFCDLL工程中实现函数ShowDLLDlg()中举行,第三种方法不同,是在MFCDllcall工程,即.exe工程中举行修改。
先将方法1和方法2的代码注释掉

在MFCDllcallDlg.cpp源文件中找到调用函数ShowDLLDlg()部分

修改后变为如下代码:
  1. void CMFCDllcallDlg::OnBnClickedDllBtn() // DLL Dialog按钮的响应函数
  2. {
  3.         // TODO: 在此添加控件通知处理程序代码
  4.         // 资源模块切换方法3:
  5.         HINSTANCE hExeInst = GetModuleHandle(NULL); //资源模块切换方法3: 取得指定模块的句柄,参数为模块的路径,返回传入路径文件的实例句柄,参数为NULL返回当前exe的实例句柄;NULL可换为_T("MFCDllcall.exe")
  6.         HINSTANCE hDLLInst = GetModuleHandle(_T("MFCDLL.dll")); //资源模块切换方法3: 注意:该路径为与MFCDllcall.exe的相对路径
  7.         ASSERT(hExeInst && hDLLInst); //资源模块切换方法3: 判断一下这两个句柄都不为空
  8.         AfxSetResourceHandle(hDLLInst); //资源模块切换方法3: 资源搜索句柄设为动态链接库的
  9.         ShowDLLDlg();
  10.         AfxSetResourceHandle(hExeInst); // 资源模块切换方法3:将资源搜索句柄变回来.exe的
  11. }
复制代码
实际上,最方便的还是第一种方法,前两种方法是在DLL导出函数中添加,第三种方法是在.exe步伐中举行添加。

总结

动态库dll与静态库lib编程4:MFC规则DLL教学。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

麻花痒

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表