拓冰建站拓冰建站
首页 / 资讯中心 / 正文

VC/MFC 安装向导源码全解析:从状态机到 Windows 安装生命周期管理

简介一份VC程序安装向导的完整源代码工程面向刚开始学习MFC编程、希望为软件作品添加标准安装界面的开发者。代码演示了如何用VC的TAB控件组织多个向导页面逐步引导用户完成欢迎、路径选择、进度展示和安装完成等典型流程工程内对话框类与页面管理分离较容易读懂。资源共26个文件包括9个头文件、8个C源文件以及资源脚本、图标、AVI动画等素材整体约48KB结构精简适合直接对照学习安装向导的整体编写思路。目前已有211人学习下载对想要掌握向导状态流转、基础控件布局与资源文件用法的VC新手来说是一份可运行的参考资料。1. 项目概述这到底是个什么东西先说结论一个简单的VC程序安装向导源代码.rar解压出来就是一个用 Visual C 和 MFC 写的自定义安装程序。它不依赖 InstallShield、NSIS 这类现成的打包工具而是把“安装向导”这个界面和背后的逻辑全部自己用代码写了一遍。很多人第一次看到这种项目会疑惑现在打包工具满地都是何必自己造轮子我实际用过之后的理解是这玩意儿最大的价值不在“装软件”而在“搞懂安装这件事本身”。你点过的“下一步”、“我同意”、“浏览选择目录”这些交互的背后是一个典型的状态机在驱动涉及界面切换、文件操作、注册表读写、快捷方式创建、卸载逻辑维护。自己动手实现一遍你对 Windows 桌面程序的整体认知会上一个台阶。这个源码适合谁两类人。一类是刚学完 MFC 对话框程序、想找个综合练习项目的学生或转行者安装向导几乎涵盖了 Windows 桌面开发的全部基础知识点另一类是想做“绿色定制版”或内部工具分发的开发者比如热词里提到的“vc定制版虚拟相机”这类带专属安装界面的工具用这套源码改改就能用——它起码能省下从零写界面框架的大量重复劳动。2. 整体设计思路为什么非要用 VC 写安装向导2.1 和现成打包工具的对比动手之前我得先捋清楚一件事现成的 NSIS 脚本或者 InstallShield 工程配置一下就能出安装包写代码做这件事是不是有点“脱裤子放屁”我把两种方案的差别排了一下对比维度现成工具NSIS等VC 手写源码开发效率高脚本配置即可低界面和逻辑都要写界面定制自由度受工具模板限制完全自由想画什么画什么学习价值基本学不到 Windows 底层机制深入理解安装的每个环节依赖情况工具自带运行时需处理 VC 运行库依赖维护成本脚本维护代码维护功能扩展更灵活这里多说一句实际工作中我用 NSIS 的时间更多因为快。但如果涉及特殊的业务逻辑——比如安装时必须采集硬件信息、按用户角色分配不同组件、跟已有的业务系统做联动校验——脚本语言写起来就非常别扭这时候自写向导反而成了唯一合理的选择。2.2 安装向导的经典状态流安装向导本质上是“分步表单”。用 MFC 实现分步表单有一个现成的方案CPropertySheetCPropertyPage。这东西就是 Windows 系统里那个黄底属性表对话框的封装天然支持“上一步 / 下一步 / 完成 / 取消”这一套标准交互。一个典型的安装流程是这样流转的欢迎页 - 许可协议页 - 安装目录选择页 - 组件选择页 - 确认安装页 - 正在安装(进度页) - 完成页每“页”就是一个CPropertyPage子类页面之间通过属性表的SetActivePage方法切换。这套机制不需要你手动控制窗口创建销毁MFC 全部给你管好了你要做的只是往每个页面上堆控件、写校验逻辑。这里有个细节值得注意CPropertySheet默认右上角只有一个关闭按钮没有“安装”那种大型品牌化界面的质感。但“简单版”嘛够用就行——你要是真想把它做得跟正经商业软件一样好看后期可以换成无边框自绘窗口那工程量就上去了。2.3 我打开源码时的第一印象解压这个 rar 之后我看到的典型文件结构是一个.dsw/.sln工程文件一个Resource.h一个resource.hm然后就是InstallSheet.cpp/.h向导框架、几个Page*.cpp/.h各步骤页面、InstallThread.cpp/.h后台文件复制线程、Uninstall.cpp/.h卸载逻辑。这个结构很清晰基本是按“界面层 逻辑层 工作线程”三层来组织的。我特别看了一下InstallThread.cpp——这就是安装过程不卡死的关键。3. 核心细节解析安装向导里最容易出问题的几个模块3.1 后台线程与进度显示安装文件的复制和注册表写入绝不能直接放在“下一步”按钮的消息响应函数里。因为这样会阻塞 UI 线程界面直接假死Windows 甚至会弹一个“程序无响应”的框框来吓用户。正确姿势是点击“安装”按钮后启动一个AfxBeginThread创建 worker 线程在线程函数里执行文件复制同时用自定义消息比如WM_PLAYER_PROGRESS把进度值回传给 UI 线程进度条控件收到消息后刷新位置。我摘一段代表性的伪代码结构UINT InstallThreadProc(LPVOID pParam) { CInstallThread* pThread (CInstallThread*)pParam; // 逐个复制文件 for (int i 0; i pThread-m_fileList.GetCount(); i) { // 复制文件... // 计算百分比 int nPercent (i 1) * 100 / pThread-m_fileList.GetCount(); // 发送进度消息给主窗口 ::PostMessage(pThread-m_hWnd, WM_PLAYER_PROGRESS, nPercent, 0); } // 写注册表、创建快捷方式... ::PostMessage(pThread-m_hWnd, WM_PLAYER_FINISHED, 0, 0); return 0; }提示消息号要自己定义比如#define WM_PLAYER_PROGRESS (WM_USER 100)。不要用系统消息号也不要跟其他控件消息撞车。3.2 安装目录的选择与磁盘空间检查“浏览”按钮通常调用SHBrowseForFolder弹出系统标准的目录选择框。选完之后要做两件事第一检查目标目录是否可写。如果你默认装到C:\Program Files (x86)\下面Win7 之后就有 UAC 权限问题需要提权或者尽量避免硬往里写。第二检查磁盘剩余空间。我见过不少初学源码直接跳过了这一步结果用户装到一半磁盘满了文件复制失败留下一堆半截文件和残留注册表项。正确做法是用GetDiskFreeSpaceEx获取目标盘剩余空间再跟待复制文件总大小对比。ULARGE_INTEGER freeBytesAvailable, totalBytes, totalFreeBytes; GetDiskFreeSpaceEx(strInstallPath, freeBytesAvailable, totalBytes, totalFreeBytes); // 如果剩余空间小于需要的大小就弹框提示并阻止安装3.3 快捷方式与注册表写入创建开始菜单快捷方式需要用到IShellLinkCOM 接口。这里有个容易踩的坑IShellLink的SetPath只能设置目标程序路径而“起始位置”工作目录必须单独SetWorkingDirectory设置否则有些程序从开始菜单启动时会因为当前目录不对而找不到资源文件。注册表这块安装向导主要处理两类。一类是卸载信息往HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\你的程序名下面写DisplayName、UninstallString、DisplayIcon等键值这样用户在“控制面板 - 程序和功能”里能看到你的程序。另一类是程序自身的配置信息比如安装路径、安装日期写到HKEY_CURRENT_USER\Software\你的程序名下面。注意写HKLM需要管理员权限建议RegisterApplicationRestart配合 UAC 清单文件从源头让程序申请以管理员身份运行。热词里提到的“vc运行库修复工具下载”这类工具普遍要写系统级位置权限问题如果不处理卸载的时候用户一怒之下把安装目录删了注册表里就留下一个死链接。4. 实操过程从编译到产出安装包4.1 编译环境与工程配置我用的是 Visual Studio 2019 / 2022打开工程后第一件事是检查字符集。这套老源码默认可能是多字节字符集MBCS而新版 VS 默认是 Unicode。如果直接编译会有一堆C2664错误等着你。热搜词里恰好有“vc常见ansi和unicode函数”这一条说明这个问题非常普遍。处理方式有两条路工程属性 - 常规 - 字符集改成多字节字符集省事但新代码再想切 Unicode 更麻烦或者把代码里的char[]、CStringA全部替换成TCHAR/CString用_T()宏包住字符串常量。我的建议是往 Unicode 迁移毕竟现在 GUID 命名都要求 Unicode。4.2 静态编译 MFC这个项目做出来的安装向导最终是要分发到目标机器上用的。如果目标机器没装 VC 运行库程序跑不起来。热搜词里“vc 2015-2022 redistribujtable”也好“vc运行库修复工具下载”也好根源都是运行库依赖。最省事的解决方案工程属性 - 常规 - MFC 的使用选“在静态库中使用 MFC”代码生成 - 运行库选“多线程 (/MT)”。这样编译出来的 exe 就是个独立程序目标机器上没装任何运行库也能跑。代价是 exe 体积会大几百 KB对安装向导这种小程序完全可以接受。4.3 安装过程的真实现场我用实际跑通的一遍流程来复盘一下关键节点。第一步“欢迎”页点击“下一步”代码里是CPropertySheet的默认行为这页基本不需要写逻辑。第二步“许可协议”页需要读一个license.rtf文件到 RichEdit 控件里。注意很多老源码用的是CRichEditCtrl::StreamIn这要求进程里必须调用一次AfxInitRichEdit2()否则控件是白屏。这个初始化函数一般放在CWinApp::InitInstance里。第三步“安装目录”页点“浏览”弹目录选择框。我建议加一个逻辑如果检测到该目录下已存在同名程序的主 exe就提示用户“检测到已安装版本是否覆盖或选择其他目录”——这个小细节能避免用户乱装出多版本冲突。第四步“正在安装”页。这页不用按钮用CPropertyPage::OnSetActive返回FALSE来隐藏系统的“下一步”按钮同时启动工作线程。等线程结束发来完成消息后再调用SetWizardButtons(PSWIZB_FINISH)把按钮变成“完成”。第五步“完成”页勾选框“运行 xxx”判断是否在OnWizardFinish里启动主程序。4.4 安装过程的“自残”与清理安装完后安装向导自己这个 exe 会留在安装目录里吗如果是正式的安装程序通常会把自己复制到临时目录运行或者引导用户运行卸载程序时删除它。删不掉的话安装目录里躺着一个多余的 exe 很碍眼。解决思路是用系统自带的cmd /c延迟删除cmd /c del /q 安装向导路径del会等进程结束才真正执行删除。这算是个小 trick但是 grep 代码里未必有你自己加就行。5. 常见问题与排查技巧实录这一节把我踩过的坑和网上高频出现的问题整理一下做成速查表。症状原因快速解决编译报错几百个 char* 转 CString 失败工程字符集是 Unicode老代码按 ANSI 写的工程属性改多字节或全局替换CString相关 API安装界面显示一堆乱码“???”源文件编码不是 UTF-8 with BOM中文注释或字符串挂掉VS 里另存为 UTF-8 with BOM或用资源文件重新翻译安装时界面假死文件复制放在了 UI 线程里按上文用AfxBeginThread移出复制逻辑卸载后控制面板残留条目卸载程序没删除注册表卸载键卸载时用RegDeleteTree删除整个卸载键安装到 Program Files 失败没有管理员权限嵌入 UAC manifestrequestedExecutionLevel levelrequireAdministrator双击安装包无反应缺少 VC 运行库静态编译 /MT或带上 redist 一起分发快捷方式指向的“起始位置”不对只调了SetPath忘了SetWorkingDirectory补上SetWorkingDirectory或用SetIconLocation设置图标5.1 字符集问题再深入一层字符集问题值得专门拿出来再说一次因为这是老源码最常见的拦路虎。VC 6.0 时代普遍用char*和 ANSI 编码而现在 VS 默认 UnicodeAPI 全变成W后缀的宽字符版本。遇到类似CString::Format(_T(%s), pszAnsi)这种混用场景格式化输出的就是乱码。我的经验是不要试图一点点替换直接全局搜索char\s*\*、char\s*[、LPSTR统一换成TCHAR*、TCHAR[、LPTSTR字符串字面量用_T()包起来。这种机械替换初期比较痛苦但一次做完后面就清爽了。5.2 文件复制失败的隐蔽原因CopyFile返回值是 BOOL很多源码不做失败检查就跳下一步。等到用户运行主程序报“缺少 xxx.dll”回头找安装日志才能发现文件没拷全。建议回调里逐文件检查返回值一旦失败弹窗提示文件名和原因并把安装标记为失败触发回滚。回滚rollback是安装向导的高级特性简单实现就是在复制之前先把已存在的文件备份到一个隐藏临时目录安装失败时把备份再拷回去。这套逻辑大概多写几十行代码但对于一个正式的安装器价值很大。6. 我对这套源码的扩展建议如果只是把源码编译通过跑一遍说实话收获有限。我更建议你动手往这几个方向加功能加完你就真正吃透它了。第一加一个“自定义组件选择”页。用CListView或者CCheckListBox展示可选组件选中的组件决定后续复制哪些文件、写哪些注册表项。这就涉及“功能与文件的映射关系”设计算是给安装器加了一点业务逻辑进去。第二加“安装日志”功能。在安装目录写一个install.log记录每一步发生的时间、文件复制结果、注册表写入情况。排查看起来一目了然现在不少开源项目甚至默认就要求带日志。第三升级 UI改成无边框的自绘窗口。去掉系统默认的CPropertySheet外观用一个普通对话框做容器手动控制页面切换和动画效果。这才是商业安装器的质感但工作量会翻倍估摸着得加一两周。最后说句实在话这套源码的核心价值不是“做出一个安装包”而是帮你把 Windows 桌面程序的“安装生命周期”完整串联了一遍。你把它的每一行读透、改造过再去用 NSIS 或者其他打包工具眼里看到的就不只是一条条脚本指令而是脚本背后真正在操作系统的哪些角落动了手脚。本文还有配套的精品资源点击获取
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门