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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

对比学习损失函数 - InfoNCE

InfoNCE Loss :构建高效对比学习模型 引言 对比学习中的InfoNCE损失函数是自监督学习领域的重要进展,它通过最大化正样本对之间的相似度并最小化负样本对的相似度,有效地引导模型学习到数据的本质特征。InfoNCE不仅提高了表示学习的质量&am…

家用万兆网络实践:紧凑型家用服务器静音化改造(二)

大家好,这篇文章我们继续分享家里网络设备的万兆升级和静音改造经验,希望对有类似需求的朋友有所帮助。 写在前面 在上一篇《家用网络升级实践:低成本实现局部万兆(一)》中,我们留下了一些待解决的问题。…

【STC库函数】Compare比较器的使用

如果我们需要比较两个点的电压,当A点高于B点的时候我们做一个操作,当B点高于A点的时候做另一个操作。 我们除了加一个运放或者比较器,还可以直接使用STC内部的一个比较器。 正极输入端可以是P37、P50、P51,或者从ADC的十六个通道…

东京大学联合Adobe提出基于指令的图像编辑模型InstructMove,可通过观察视频中的动作来实现基于指令的图像编辑。

东京大学联合Adobe提出的InstructMove是一种基于指令的图像编辑模型,使用多模态 LLM 生成的指令对视频中的帧对进行训练。该模型擅长非刚性编辑,例如调整主体姿势、表情和改变视点,同时保持内容一致性。此外,该方法通过集成蒙版、…

海思Linux(一)-Hi3516CV610的开发-ubuntu22_04环境创建

目 录 前 言 一、芯片介绍 二、环境搭建 2.1 前提准备 2.2 虚拟机创建 2.3 ubuntu环境安装 2.4 基础ubuntu环境搭建 2.5 使用MobaXterm登陆ubuntu 前 言 芯片选型:HI3516CV610 选择的开发板是:酷电科技馆的Hi3516CV610-MINI开发板 上一篇文章&#xf…

vue elementUI Plus实现拖拽流程图,不引入插件,纯手写实现。

vue elementUI Plus实现拖拽流程图,不引入插件,纯手写实现。 1.设计思路:2.设计细节3.详细代码实现 1.设计思路: 左侧button列表是要拖拽的组件。中间是拖拽后的流程图。右侧是拖拽后的数据列表。 我们拖动左侧组件放入中间的流…

Spring boot 项目 Spring 注入 代理 并支持 代理对象使用 @Autowired 去调用其他服务

文章目录 类定义与依赖注入方法解析createCglibProxy注意事项setApplicationContext 方法createCglibProxy 方法 类定义与依赖注入 Service: 标识这是一个 Spring 管理的服务类。ApplicationContextAware: 实现该接口允许你在类中获取 ApplicationContext 对象,从而…

应用程序越权漏洞安全测试总结体会

应用程序越权漏洞安全测试总结体会 一、 越权漏洞简介 越权漏洞顾名思议超越了自身的权限去访问一些资源,在OWASP TOP10 2021中归类为A01:Broken Access Control,其本质原因为对访问用户的权限未进行校验或者校验不严谨。在一个特定的系统或…

JAVA:Spring Boot 集成 Quartz 实现分布式任务的技术指南

1、简述 Quartz 是一个强大的任务调度框架,允许开发者在应用程序中定义和执行定时任务。在 Spring Boot 中集成 Quartz,可以轻松实现任务的调度、管理、暂停和恢复等功能。在分布式系统中,Quartz 也支持集群化的任务调度,确保任务…

改善 Kibana 中的 ES|QL 编辑器体验

作者:来自 Elastic Marco Liberati 随着新的 ES|QL 语言正式发布,Kibana 中开发了一种新的编辑器体验,以帮助用户编写更快、更好的查询。实时验证、改进的自动完成和快速修复等功能将简化 ES|QL 体验。 我们将介绍改进 Kibana 中 ES|QL 编辑器…

【深度学习入门_基础篇】线性代数本质

开坑本部分主要为基础知识复习,新开坑中,学习记录自用。 学习目标: 熟悉向量、线性组合、线性变换、基变换、矩阵运算、逆函数、秩、列空间、零空间、范式、特征指、特征向量等含义与应用。 强烈推荐此视频: 【官方双语/合集】…

【SpringBoot】当 @PathVariable 遇到 /,如何处理

1. 问题复现 在解析一个 URL 时,我们经常会使用 PathVariable 这个注解。例如我们会经常见到如下风格的代码: RestController Slf4j public class HelloWorldController {RequestMapping(path "/hi1/{name}", method RequestMethod.GET)publ…

VBA(Visual Basic for Applications)编程|excel|一系列网址或文件路径快速转换为可点击的超链接

很多时候,我们需要把导入的数据某一列转换成超链接,比如URL形式的列。 那么,大批量的情况下,无疑一个个手动点击是非常愚蠢的办法,这个时候我们就需要VBA编程来编写宏,通过编写宏来简化这些手动操作并不现…

小程序开发全解析 快速构建高效应用的核心指南

内容概要 小程序开发是当前数字世界中炙手可热的领域,吸引了无数开发者和企业的关注。随着技术的进步,小程序成为了提升用户体验、增强品牌曝光以及增加客户互动的重要工具。了解小程序的基本概念,就像是打开了一扇通往新世界的大门。 在这…

SQL—Group_Concat函数用法详解

SQL—Group_Concat函数用法详解 在LC遇见的一道很有趣的SQL题,有用到这个函数,就借这道题抛砖引玉,在此讲解一下group_concat函数的用法。🤣 GROUP_CONCAT([DISTINCT] expression [ORDER BY expression] [SEPARATOR separator])…

Edge Scdn的应用场景有哪些?

酷盾安全Edge Scdn 具备强大的安全防护能力,通过多层防御机制,如防火墙、DDoS 攻击防护、入侵检测和防御、数据加密等,有效抵御各种网络攻击,包括 DDoS 攻击、CC 攻击、SQL 注入攻击、XSS 跨站脚本攻击等,保障网站和应…

流光效果

1、流光效果是什么 在 Unity Shader 中的流光效果是一种动态的视觉效果,通常用于给材质增加一种闪光或光线移动的效果,使物体表面看起来像是有光在流动。这种效果常用于武器光效、能量护盾、传送门等等,可以让物体看起来更加生动富有科技感 …

滑动窗口——串联所有单词的子串

一.题目描述 30. 串联所有单词的子串 - 力扣(LeetCode) 二.题目解析 题目前提:s是一个字符串,words是一个字符串数组,里面所有的字符串的长度都是相等的。 题目要求:找到s中的一段连续的子串&#xff0…

【微软,模型规模】模型参数规模泄露:理解大型语言模型的参数量级

模型参数规模泄露:理解大型语言模型的参数量级 关键词: #大型语言模型 Large Language Model #参数规模 Parameter Scale #GPT-4o #GPT-4o-mini #Claude 3.5 Sonnet 具体实例与推演 近日,微软在一篇医学相关论文中意外泄露了OpenAI及Claud…

SpringBoot Maven 项目 pom 中的 plugin 插件用法整理

把 SpringBoot Maven 项目打包成 jar 文件时,我们通常用到 spring-boot-maven-plugin 插件。 前面也介绍过,在 spring-boot-starter-parent POM 和 spring-boot-starter POM 中都有插件的管理,现在我们就撸一把构建元素中插件的用法。 一、…