动态库dll与静态库lib编程4:MFC规则DLL讲解

文章目录

  • 前言
  • 一、说明
  • 二、具体实现
    • 2.1新建项目
    • 2.2 模块切换的演示
  • 总结


前言

动态库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讲解。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/891910.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【JVM】总结篇-类的加载篇之 类的加载器 和ClassLoader分析

文章目录 类的加载器ClassLoader自定义类加载器双亲委派机制概念源码分析优势劣势如何打破Tomcat 沙箱安全机制JDK9 双亲委派机制变化 类的加载器 获得当前类的ClassLoader clazz.getClassLoader() 获得当前线程上下文的ClassLoader Thread.currentThread().getContextClassLoa…

数据挖掘——回归算法

数据挖掘——回归算法 回归算法线性回归最小二乘法优化求解——梯度下降法逻辑回归逻辑回归函数逻辑回归参数估计逻辑回归正则化 决策树回归小结 回归算法 回归分析 如果把其中的一些因素(房屋面积)作为自变量,而另一些随自变量的变化而变化…

前端如何从入门进阶到高级

在前端学习的道路上,我们将其划分为三个阶段:入门、实战和进阶。以下是各阶段的学习指南 一、入门阶段 在入门阶段,我们的目标是掌握前端的基本语法和知识,以便能够独立解决一些基础问题。这一阶段,我们建议通过视频…

Android14 CTS-R6和GTS-12-R2不能同时测试的解决方法

背景 Android14 CTS r6和GTS 12-r1之后,tf-console默认会带起OLC Server,看起来olc server可能是想适配ATS(android-test-station),一种网页版可视化、可配置的跑XTS的方式。这种网页版ATS对测试人员是比较友好的,网页上简单配置下…

Linux中的tcpdump抓包命令详解:抓取TCP和UDP数据包并按小时输出文件

Linux中的tcpdump抓包命令详解:抓取TCP和UDP数据包并按小时输出文件 一、tcpdump简介二、安装tcpdump三、抓取TCP和UDP数据包四、按小时输出文件五、tcpdump命令的常用选项和表达式六、总结在Linux系统中,tcpdump是一款强大的网络抓包工具,它基于libpcap库开发,可以捕获网络…

k8s基础(4)—Kubernetes-Service

Service概述 抽象层 ‌k8s的Service是一种抽象层,用于为一组具有相同功能的Pod提供一个统一的入口地址,并通过负载均衡将网络流量分发到这些Pod上。‌ Service解决了Pod动态变化的问题,例如Pod的IP地址和端口可能会发生变化,通过…

国内Ubuntu环境Docker部署CosyVoice

国内Ubuntu环境Docker部署CosyVoice 本文旨在记录在 国内 CosyVoice项目在 Ubuntu 环境下如何使用 dockermin-conda进行一键部署。 源项目地址: https://github.com/FunAudioLLM/CosyVoice 如果想要使用 dockerpython 进行部署,可以参考我另一篇博客中的…

基于 gitlab-runner 实现调度GPU的资源

本篇目录 1. 客户需求2. 需求调研3. 实践3.1 方案一:环境变量的方式3.2 方案二:k8s 自身的spec注入机制 4. 效果 该实践来自于客户的一个真实需求 1. 客户需求 客户的某些流水线需要使用GPU资源,但是对于GPU服务器而言,会有多张G…

计算机网络 —— 网络编程(TCP)

计算机网络 —— 网络编程(TCP) TCP和UDP的区别TCP (Transmission Control Protocol)UDP (User Datagram Protocol) 前期准备listen (服务端)函数原型返回值使用示例注意事项 accpect (服务端)函数原型返回…

模型 九屏幕分析法

系列文章 分享 模型,了解更多👉 模型_思维模型目录。九屏幕法:全方位分析问题的系统工具。 1 九屏幕分析法的应用 1.1 新产品研发的市场分析 一家科技公司计划开发一款新型智能手机,为了全面评估市场潜力和风险,他们…

Unity2D初级背包设计中篇 MVC分层撰写(万字详解)

本人能力有限,如有不足还请斧正,理论分析链接如下: Unity2D初级背包设计前篇 理论分析-CSDN博客 目录 1.M层:数据存储 物品 仓库容器 加载方式 2.M层:逻辑撰写 InventoryManager 仓库的管理 SlotData 物品的增…

深入理解 Linux 管道:创建与应用详解(匿名管道进程池)

在现代操作系统中,进程间通信(IPC)是实现多任务、多进程协作的关键技术之一。Linux 提供了多种 IPC 机制,本博客将帮助您详细的理解进程间通信的原理 首先,在学习管道之前,我们先理解一下管道的存在是为了什…

SWM221系列芯片之电机应用及控制

经过对SWM221系列的强大性能及外设资源,TFTLCD彩屏显示及控制进行了整体介绍后,新迎来我们的电控篇---SWM221系列芯片之电机应用及控制。在微控制器市场面临性能、集成度与成本挑战的当下,SWM221系列芯片以其卓越性能与创新设计,受…

Trimble天宝X9三维扫描仪为建筑外墙检测提供了全新的解决方案【沪敖3D】

随着城市化进程的快速推进,城市高层建筑不断增多,对建筑质量的要求也在不断提高。建筑外墙检测,如平整度和垂直度检测,是衡量建筑质量的重要指标之一。传统人工检测方法不仅操作繁琐、效率低下,还难以全面反映墙体的真…

机器人手眼标定

机器人手眼标定 一、机器人手眼标定1. 眼在手上标定基本原理2. 眼在手外标定基本原理 二、眼在手外标定实验三、标定精度分析 一、机器人手眼标定 要实现由图像目标点到实际物体上抓取点之间的坐标转换,就必须拥有准确的相机内外参信息。其中内参是相机内部的基本参…

unity中的UI系统---GUI

一、工作原理和主要作用 1.GUI是什么? 即即时模式游戏用户交互界面(IMGUI),在unity中一般简称为GUI,它是一个代码驱动的UI系统。 2.GUI的主要作用 2.1作为程序员的调试工具,创建游戏内调测试工具 2.2为…

Java开发 PDF文件生成方案

业务需求背景 业务端需要能够将考试答卷内容按指定格式呈现并导出为pdf格式进行存档,作为紧急需求插入。导出内容存在样式复杂性,包括特定的字体(中文)、字号、颜色,页面得有页眉、页码,数据需要进行表格聚…

SpringCloud微服务架构

文章目录 认识微服务:SpringCloud 服务拆分及远程调用实现夸远程服务调用使用RestTemplateEureka注册中心 搭建EruekaServer注册服务服务发现 Ribbon负载均衡 修改负载均衡规则解饿加载 Nacos注册中心(nacos一部分功能) 服务注册到nacosnacos…

【设计模式-02】23 种设计模式的分类和功能

在软件工程领域,设计模式是解决常见设计问题的经典方案。1994 年,Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides(四人帮,GoF)在《设计模式:可复用面向对象软件的基础》一书中系统性地总结了…

简历_专业技能_熟悉分布式锁Redisson的原理以及使用

系列博客目录 文章目录 系列博客目录怎么样才能够在简历上写熟悉redisson的应用以及原理1. 清晰描述技能与经验示例: 2. 列举具体应用场景示例项目经验: 3. 展示你对原理的理解示例: 4. 用简历中的关键词突出你的能力示例段落: 5.…