先问一个我遇到过很多次的问题:你在自己电脑上辛辛苦苦用 VS2022 编译好的 Qt 程序,拷到客户机器上,双击 exe,程序闪退,或者弹出缺少 DLL 的提示……这种情况几乎每个做 Qt 桌面开发的都会碰到。原因一点都不神秘,就是依赖没带上。Qt 程序不像单文件 exe 那样干净,它依赖一堆 Qt 运行库、编译器运行库,甚至平台插件。如果是做设备类软件,可能还要连驱动程序一起给客户装好。所以把这套东西做成一个 Setup 安装程序,一次性把程序本体、运行依赖、驱动全部塞进去,才是稳妥的交付方式。
这一篇我就把我这边打包 Qt 程序的全套流程完整梳理一遍。环境是 Visual Studio 2022 + Qt 6.x(msvc 版本),最终产出一个 setup.exe 或 .msi 格式的安装包。整个流程不复杂,但里面有不少坑,比如 windeployqt 该不该带参数、驱动文件怎么进安装包、自定义操作要怎么配置,每一步不到位,装到客户机器上就会出幺蛾子。下面每个环节我都会讲清楚为什么这么做,以及实际操作中会踩到哪些雷。
1. 打包前的整体思路:先想清楚到底要交付什么
1.1 为什么直接拷贝 exe 会缺依赖
Qt 程序在开发机编译时,链接器会把程序需要的 Qt 动态库路径写进 exe 的导入表里面。你在自己电脑上能跑,是因为 Qt 的运行库、编译器运行库都在系统 PATH 里,或者就在开发环境目录下。到了客户机器上,这些路径不存在,系统按照导入表找不到 DLL,结果就是启动失败。
更隐蔽的是 Qt 的插件机制。Qt 程序启动窗口时,会从 exe 所在目录的 platforms 子目录下加载平台插件。如果你只是把 exe 和几个核心 DLL 拷过去,少了 platforms/qwindows.dll,程序可能在 main 函数里直接崩溃,连错误提示都不弹。类似的还有 styles 目录里的样式插件、imageformats 目录里的图片格式插件。这些目录结构必须在可分发的文件夹里原样保留。
所以打包之前要有一个明确的概念:你交付的不仅仅是一个 exe,而是“exe + Qt 运行库 + 插件目录 + 可能的第三方 DLL + 可能的驱动文件”这一整套东西。把这套东西整理干净,再用安装程序包装起来,才是正确的交付思路。
1.2 安装包方案选型:VS Installer 项目还是第三方工具
做 Windows 安装包的办法很多,NSIS、Inno Setup、InstallShield、WiX 都有大量用户。但如果你的主开发环境就是 Visual Studio 2022,并且不想引入额外学习成本,最简单直接的做法是装一个官方扩展:Microsoft Visual Studio Installer Projects。装完之后,VS 里就能直接新建 Setup 项目,把主项目的输出、依赖文件、注册表项、快捷方式、自定义操作都管理起来,编译直接产出安装包。
这个方案对“Qt + 驱动”这种组合特别合适,原因有几点:
- 它能合并主项目的所有依赖输出,人工干预少。
- 它支持文件系统视图,驱动文件可以单独放到安装目录下的特定子目录,不影响程序目录整洁。
- 它支持自定义操作,驱动安装程序可以被安装包在“安装完成后”阶段自动触发。
- 它生成的 .msi 或 setup.exe 符合 Windows Installer 规范,控制面板里能正常卸载。
当然,如果你的场景是“极简绿色版软件,不要任何安装过程”,那直接打一个压缩包反而更省事。但既然标题里说了要打包驱动和依赖,说明面向的是偏工业、偏设备的场景,客户现场大概率需要一键装到位,所以安装程序是合理选择。
1.3 全流程的六个关键阶段
我先把我实际操作时走过的完整链路列出来,方便你心里有个全局框架:
- 编译准备:切换到 Release 模式,并确保编译产物的运行环境是干净的。
- 依赖收集:用 windeployqt 把 Qt 的 DLL、插件、翻译文件全部拉取到输出目录。
- 依赖检查:人工检查第三方 DLL,比如 openssl、msvcp140.dll 等是否遗漏。
- 安装项目配置:在 VS2022 里创建 Setup 项目,添加主输出和驱动文件。
- 驱动接入:把 .inf / .sys / .cat 或驱动安装工具放进专门的目录,并用自定义操作触发安装。
- 验证发布:在干净虚拟机里跑一遍安装、启动、卸载,确认无残留。
这六个阶段里,第三、五阶段最容易被人忽略。很多人打包完以为自己搞定了,结果到客户现场才发现少了一个 ICU 数据文件,或者驱动没有静默安装成功。下面每个阶段我都掰开揉碎讲。
2. 环境准备与基础配置
2.1 安装 Visual Studio Installer Projects 扩展
VS2022 默认不自带安装项目模板,需要从扩展市场下载 Microsoft Visual Studio Installer Projects。打开 VS2022,进入“扩展”菜单,选择“管理扩展”,搜索 “Installer Projects”,找到 Microsoft 官方发布的那一个,点击下载,然后关闭 VS,按提示完成安装。
装好后重新打开 VS,新建项目时你会在模板列表里看到三类:
- Setup Project:生成 .msi 安装包,适合一般应用。
- Installer Project:生成 setup.exe + 多个文件,适合需要引导框架的场景。
- Merge Module Project:合并模块,一般用于封装可复用的依赖组件,不直接用来做最终安装包。
正常做 Qt 程序,我建议选 Setup Project。它生成的是标准 Windows Installer 包,双击即可安装。如果你的软件还需要在安装前检查运行环境、需要在线下载内容,那才需要 Installer Project 那种带引导器的方案。后面我基于 Setup Project 展开。
2.2 Qt 与 MSVC 编译器匹配
Qt 有 MSVC 版本和 MinGW 版本,VS2022 的 Qt 开发必须用 MSVC 对应版本,比如 Qt 6.5.0 的 msvc2019_64 或 msvc2022_64,这取决于你装的 Qt 套件。如果版本对不上,会出现 QMAKE 编译错误或链接失败。
打包阶段也要记得保持同一套工具链。比如你用 Qt 6.5 + MSVC 2022 编译的 exe,就必须用同一个 Qt 套件下的 windeployqt 来收集依赖,混用版本会让 DLL 和 exe 的 C++ 运行时不一致。这种情况比较隐蔽,程序可能在开发机上正常,在客户机器上偶发崩溃,跟编译器运行时初始化失败有关。
2.3 Release 模式编译是铁律
给客户打包,绝对不要用 Debug 模式。Debug 版依赖的调试运行库在客户电脑上不会存在,而且体积大、速度慢。在 VS2022 的解决方案配置里切到 Release,然后重新生成。
生成完之后建议直接在“调试”菜单里选择“启动但不调试”,快速验证一下 Release 版程序能正常打开。这里可以看到 Qt 加载了哪些插件、有没有报数据库驱动问题,比直接拷到客户机再排查省事得多。
2.4 项目目录规划
我习惯在解决方案根目录下建一个 release_bundle 文件夹,专门用来放将要被打包的内容。所有 windeployqt 的输出都先进这个文件夹,然后再把第三方 DLL、驱动文件夹往里放。这样做的好处是干净,安装项目里你要添加的文件范围明确,不会把开发机上的垃圾文件、pdb 调试符号之类的东西也打进去。
3. 依赖收集:windeployqt 的正确使用姿势
3.1 windeployqt 到底帮你做了什么事
windeployqt 是 Qt 自带的部署工具,它会扫描你指定的 exe,分析导入表,把 Qt 模块的 DLL 复制到目标目录,同时创建 platforms、styles、imageformats、iconengines 等插件子目录,按需复制插件。对于 Qt 6,它还会处理 QML 模块、翻译文件、ICU 数据等。
它解决的最大问题不是“复制 DLL”,而是“识别该复制哪些 DLL”。如果你手工会漏,用工具就不会漏。但 windeployqt 也不是万能的,它对第三方非 Qt DLL 处理能力有限,比如你自己链接的 openssl、pthread、某个采集卡 SDK,它不会管。这部分依赖需要你手工补充。
3.2 手动执行 windeployqt 的标准命令
假设你的 Release 输出在x64\Release\App.exe,需要先把这个 exe 拷贝到目标目录,再在目标目录下执行:
windeployqt.exe --release --no-translations --no-opengl-sw --no-system-d3d-compiler App.exe参数含义如下:
--release:对应 Release 模式,不要和 Debug 混着用。--no-translations:除非你的程序需要多语言界面,否则可以不复制翻译文件,节省体积。--no-opengl-sw:不复制软件 OpenGL 库。桌面 UI 程序一般用不到。--no-system-d3d-compiler:不强制复制旧版 D3D 编译器 DLL。如果你的 Qt 版本需要,装完测试时如果发现报错,再把这参数去掉重新跑一次。
执行完之后,目标目录下会出现 App.exe、一堆 Qt6*.dll,以及 platforms、styles 等子目录。这时可以先双击 App.exe 看看能不能正常启动。如果报缺少某个 DLL,到开发机 Qt 安装目录里找同名 DLL 复制过去,再试。
3.3 把 windeployqt 集成到 VS 构建事件里
每次手动敲命令容易忘,我建议把它写进 Visual Studio 的项目“生成事件 -> 生成后事件”,这样每次编译完,依赖自动被收集到指定目录。
在“生成后事件命令行”里写:
xcopy /Y "$(TargetDir)App.exe" "$(SolutionDir)release_bundle\" "C:\Qt\6.5.0\msvc2022_64\bin\windeployqt.exe" --release --no-translations --no-opengl-sw "$(SolutionDir)release_bundle\App.exe"注意两点:
- windeployqt 的路径要和你安装的 Qt 版本一致,写绝对路径最省心。
- target 目录里如果已有残留旧 DLL,最好先清空再执行,否则可能混入旧版本文件。
我在实际项目里就遇到过这个问题:某一次 Qt 小版本升级后,release_bundle 目录里残留的旧版本 qwindows.dll 没被覆盖,结果客户机器上一部分界面显示异常,排查了半天才意识到是旧插件文件的问题。
3.4 第三方依赖的识别与补齐
windeployqt 跑完,还需人工检查 exe 依赖的第三方 DLL。最简单的方法是用 “Dependencies” 工具打开 exe,它能直观列出所有 DLL 依赖和缺失项。
常见需要手工补充的有:
msvcp140.dll、vcruntime140.dll:MSVC 运行库,Qt 6 的 MSVC 版本和你的编译器都会用到。Windows 10/11 大部分版本自带,但“精简版”系统或老系统未必有,建议一并放进目录。openssl:Qt 的网络模块如果启用了 SSL,就需要 libssl 和 libcrypto。windeployqt 有时会处理,但版本不一定匹配你程序的实际需求,最好手工确认。- 设备厂商 SDK:比如扫码枪、打印机的动态库,这些通常在你的项目源码目录里,需要手动复制到 release_bundle。
补齐之后再双击测试,直到 exe 在“不含任何 Qt 环境”的干净目录下能正常启动,这一阶段才算过关。
4. 驱动打包:把驱动也塞进安装程序的两种做法
4.1 先搞清楚驱动安装的机制
Windows 驱动不是简单拷贝一个 .sys 文件就能生效的,需要经过安装环节,让系统读取 INF 文件,把驱动注册进驱动仓库,并为对应设备创建服务。常见的做法分两条路:
第一种:把驱动源文件(.inf / .sys / .cat)放进安装目录,在安装完成后用自定义操作调用系统的 RUNDLL32 或厂商提供的驱动安装工具来静默安装。
第二种:如果你的硬件设备支持 WinUSB 或免驱方案,那安装包里其实只需要带一个 INF 文件,配合自定义操作执行pnputil.exe /add-driver xxx.inf /install来完成驱动安装。这种方式特别适合大多数 USB 设备。
我这里主要讲第二种,因为它依赖少、可控性强,而且是目前设备类软件最常用的方式。如果你的驱动是签名的 WHQL 驱动,那流程会更顺;如果驱动未签名,客户机器可能需要先禁用驱动签名强制策略,这属于另一个话题,本文不展开。
4.2 驱动文件的准备与目录安排
在 release_bundle 目录下建一个 driver 子目录,把以下文件放进去:
device.inf:驱动的安装信息文件,里面定义了设备的硬件 ID 和 CopyFiles 逻辑。device.sys:驱动核心文件。device.cat:数字签名目录文件。
如果厂商的驱动安装说明里要求把文件放到特定目录,那就不要乱改,严格按 INF 文件里 SourceDisksFiles 段的相对路径来摆放。很多时候 INF 文件里写的是“从安装包当前目录读取文件”或“从某子目录读取文件”,你只要保证安装完成后这些文件还在原地就行。
这里有个容易踩的坑:INF 文件里的路径如果用了反斜杠和空格,某些版本的安装工具会解析失败。所以驱动子目录名尽量不要带空格。你在安装项目里给 driver 文件夹加文件时,也要保持相对路径一致,不要自作主张重命名文件。
4.3 在 Setup 项目里添加驱动文件夹
打开你创建的 Setup Project,在“目标计算机上的文件系统”编辑器里,右键“添加”->“文件夹”,命名为 driver。再选中该文件夹,右键“添加”->“文件”,把 release_bundle 里的device.inf、device.sys、device.cat加进去。
确保这个文件夹位于应用的安装目录下,也就是[ProgramFilesFolder][Manufacturer]\[ProductName]\driver。在安装项目里,最终安装路径用的是方括号格式的变量,这点要熟悉,否则你会发现文件被装到了意想不到的位置。安装场景中常见的路径变量包括:
[ProgramFilesFolder]:程序文件目录,64 位应用通常装到 Program Files。[Manufacturer]:你在安装项目属性里填写的厂商名。[ProductName]:项目名。[WindowsFolder]:Windows 系统目录。
如果你不想让驱动文件暴露在用户能随便翻到的地方,也可以把它装到[ProgramFilesFolder][Manufacturer]\[ProductName]\driver,这已经够用了。再深一层可以放[CommonAppDataFolder]下,但那通常需要额外权限配置。
4.4 用自定义操作触发驱动安装
这是打包驱动最关键的环节。在 Setup 项目里,右键点击“自定义操作”节点,展开可以看到“安装”、“提交”、“回滚”、“卸载”四个阶段。驱动安装应该放在“安装”阶段,因为这是实际往系统写入驱动的操作。
添加自定义操作的方法是:在“安装”节点上右键,选择“添加自定义操作”,然后在“应用程序文件夹”里选中刚才的那个 driver 文件夹,选择一个可执行文件来触发驱动安装。这里有个问题:INF 文件本身不是可执行文件,不能直接作为自定义操作。所以你需要一个能执行驱动安装命令的工具。
两个常见选择:
- 使用
pnputil.exe,这是 Windows 自带的驱动安装工具,路径在C:\Windows\System32\Pnputil.exe。你可以添加自定义操作指向它,并把参数设置为/add-driver device.inf /install。但因为自定义操作默认的工作目录是安装目录而非 driver 子目录,参数里的 INF 路径最好写成绝对路径。 - 使用驱动厂商提供的安装辅助 exe,比如很多硬件厂商会提供一个 SilentInstall.exe,它内部负责调用 dpinst 或 pnputil。这种最简单,直接把 SilentInstall.exe 加进 driver 文件夹,自定义操作指向它就行。
我实际操作时更倾向用 pnputil.exe,因为不需要额外携带工具文件。自定义操作的参数里写作:
/add-driver "[ProgramFilesFolder][Manufacturer]\[ProductName]\driver\device.inf" /install加完自定义操作后,VS 会弹出一个确认框,问你“自定义操作将不受回滚保护,是否确认”,这类提示一般是基于权限和回滚机制的说明。建议选“是”,但你要知道,如果驱动安装本身失败,Windows Installer 的回滚机制不一定能帮你恢复,所以安装前最好先在测试机验证一次 pnputil 命令是否单独执行成功。
5. 创建 Setup 安装项目:一步步配置
5.1 新建 Setup Project 并设置 Product 属性
在解决方案里右键“添加”->“新建项目”,搜索 Setup Project,命名为比如“AppSetup”,然后回车。等 VS 创建完成后,打开属性窗口,需要设置的关键属性有:
ProductName:显示给用户看的软件名称,比如“设备管理终端 6.0”。Manufacturer:厂商名,会出现在默认安装路径和添加删除程序里。Version:安装包版本。InstallAllUsers:选择 true 以安装到所有用户,设备类软件基本都选 true,因为驱动和服务需要系统级权限。
如果不设置 Manufacturer,默认会变成你的工程名,安装路径里就会带一个奇怪的名字,不专业。
5.2 添加应用主输出
Setup 项目创建完成后,在“文件系统编辑器”里默认有一个“应用程序文件夹”。右键点击这个文件夹,选择“添加”->“项目输出”,在弹出的对话框里,选择你的主 Qt 工程,再选择“主输出”。
这一步很重要:VS 要分析项目输出,所以主工程必须在同一个解决方案里。如果你的 Qt 工程是 .pro 文件管理的,需要先让 CMake 或 VS 方案生成一个可用于 VS 部署的项目输出。实际中更常见的做法是把 release_bundle 目录里所有文件全部添加进应用文件系统,这样可控性更强。
我习惯的做法是:在“应用程序文件夹”里,右键“添加”->“文件夹”,命名为“bin”,然后把 release_bundle 下的 exe、DLL、插件目录全部加进去。接着右键“添加”->“文件”,选中 release_bundle 根目录下的所有文件和子目录。
如果你用“项目输出”方式,VS 会自动追踪依赖,但 Qt 的插件目录和 windeployqt 生成的非标准文件它是不懂的,所以混合方案更稳:项目输出用于 exe 本体,手加文件夹用于 Qt 依赖。当然,纯手加也不难,就是文件多了以后列表会比较长。
5.3 设置快捷方式与桌面图标
很多设备软件装完要在桌面和开始菜单都有入口,Setup 项目支持在“文件系统编辑器”里右键“应用程序文件夹”里的 exe,选择“创建快捷方式”,然后把快捷方式拖到“用户的程序菜单”或“用户桌面”文件夹。
这里有个细节:Qt 程序如果要显示自定义的 exe 图标,你必须在编译时把图标编译进 exe 资源,或者通过 Qt 的 .rc 文件设置图标。仅靠安装项目是没法给没有图标资源的目标程序贴图标的。所以如果你的 exe 没有图标,先回到 Qt 工程,在 .pro 文件里加:
RC_ICONS = myapp.ico重新编译后再做安装包。
5.4 注册表项与文件关联
如果你的程序需要写注册表,可以在“目标计算机上的文件系统”右键选择“查看”->“注册表”,然后在注册表编辑器里添加键值。注意安装项目的注册表编辑器展示的是“目标系统注册表的视图”,它把 HKLM、HKCU 的关键分支都列出来了,但不会显示完整根键名。你在添加键时选择 HKEY_LOCAL_MACHINE 或 HKEY_CURRENT_USER 下面的对应分支即可。
对设备类软件,我建议尽量避免写 HKLM,能写 HKCU 就写 HKCU,因为运行安装程序的不一定是管理员,写入 HKLM 可能触发 UAC 权限问题。但如果你的软件需要为所有用户配置串口号或设备信息,那 HKLM 就不可避免,此时安装项目属性里“安装所有用户”要设成 true,并且自定义操作必须以管理员权限执行。
5.5 卸载支持与 Add/Remove Programs 信息
Setup 项目默认会生成卸载信息,只要你的安装包是标准 MSI,用户就能在“设置 -> 应用”里卸载。如果你希望卸载时也把驱动去掉,那需要在“卸载”阶段的“自定义操作”里添加对应命令,比如:
pnputil.exe /remove-device "设备实例ID"或者对 INF 包执行:
pnputil.exe /delete-driver device.inf /uninstall不过卸载驱动有一个敏感点:如果系统里有其他设备正在使用该驱动,强制卸载会引发问题。我一般不在卸载时自动删驱动,而是留给用户手动卸载,或者安装包提示用户“驱动文件将保留在系统中,以便后续自动更新”。这样更安全,也避免被客户误操作导致设备变砖。
5.6 编译 Setup 项目,产出安装包
一切配置完成后,右键 Setup 项目,选择“生成”。默认情况下输出是一个 .msi 文件和一个 setup.exe 引导文件。生成路径一般在 Setup 项目的Release文件夹下。
需要提醒的是,第一次编译 Setup 项目时,VS 会进行依赖扫描,如果有文件被其他进程占用,比如你还在运行 release_bundle 里的 App.exe,它可能会导致编译中断。编译前把正在运行的被安装程序关闭,这是一个容易忽略的细节。
6. 安装包验证与常见问题排查
6.1 在干净环境里做一次全流程验证
打包完不要急着发给客户,先找一台没有安装过任何 Qt 运行时的干净虚拟机,把安装包拷进去,执行安装,然后检查:
- 安装完成后,桌面和开始菜单有没有快捷方式。
- 双击启动软件,确认不闪退、界面正常。
- 设备管理器里能否看到驱动已成功安装,或“通用串行总线设备”是否正常枚举。
- 功能上操作一遍软件主要流程,比如数据采集、打印、设备通信。
- 去“设置 -> 应用”卸载软件,确认程序文件被删除,但用户数据文件没有被误删。
这一套走完,才能算真正的“能交付”。我在公司做过一次打包体检,测试机上一开始就缺了msvcp140.dll,因为那台虚拟机是精简版 Windows,没有装任何 VC++ 运行库。虽然 windeployqt 本身不会把 MSVC 运行库全覆盖,但如果你之前没注意,这就是会被客户当场发现的典型问题。
6.2 常见问题速查与解决建议
下面这张表是我打包过程中遇到的高频问题,按出现频率排序:
| 现象 | 原因 | 解决办法 |
|---|---|---|
| 安装后启动提示缺少 Qt6Core.dll | windeployqt 未复制完整 | 重新运行 windeployqt,确保 exe 和 DLL 在同一个 run 目录 |
| 启动后程序崩溃,事件查看器里报异常模块是 qwindows.dll | platforms 目录缺失或版本不匹配 | 用 windeployqt 重新生成 platforms/qwindows.dll,确认 Qt 版本一致 |
| 驱动未安装,设备管理器里出现黄色感叹号 | 自定义操作参数里的 INF 路径不对 | 检查是否使用了方括号路径变量,手动执行 pnputil 验证 |
| 安装包非常大,接近几百兆 | 包含 Debug 体积、pdb 文件、无用的示例文件 | 清理 release_bundle 下的调试文件,只留 Release 输出 |
| 安装到一半提示“找不到文件” | Setup 项目里的文件夹结构改成非预期 | 检查安装项目文件系统编辑器,确认每个文件都在预期目录下 |
| 卸载后程序还在运行 | 自定义操作未结束进程 | 在卸载自定义操作里调用 taskkill /im App.exe /f |
6.3 几个容易被忽略的操作细节
一是关于 Windows 服务。如果你的程序本身不是服务,但依赖的系统服务没有被安装包集成,客户现场容易出问题。比如依赖 SQL Server 或某个中介服务,建议在“启动条件”里加检测条件,若检测不到服务则提示安装依赖。
二是关于 x64 / x86 的区分。如果客户机器可能是 32 位系统,那你必须用 32 位 Qt 套件重新编译一次,并重新用对应版本的 windeployqt 部署。64 位安装包不能装进 32 位系统里面,打包前先问清楚客户环境,不然只能到现场再返工。
三是关于 pdb 符号文件。VS 生成 C++ 项目时默认会生成 .pdb 文件,这些文件体积不小。打包时不要让它们进 release_bundle,除非你需要做崩溃分析。我在发布目录里保留 .pdb 用于本地定位崩溃,但安装包里绝对不放,没必要让客户也下载。
四是关于版本号管理。Setup 项目的属性里有一个版本号,务必要和主程序的版本号保持一致。很多软件出现“安装的是 2.0,但卸载时显示 2.0.0.1”或者“改了程序版本但安装包版本没变”的情况,对售后排查问题很不友好。
7. 最后的一些实操心得
打包这件事,看起来是几个简单的步骤,实际上每一步都有明显的“现场感”。同样是 windeployqt,有人跑完就以为没事了,我跑完还会手工打开 dumpbin 或 Dependencies 工具扫一遍。因为打包本身不创造新功能,你只是把已经存在的东西按用户预期的方式送到他们机器上,所以严谨比创意更重要。
如果这套流程你第一次走,建议从一个小项目开始练手,不要一上来就打包带有驱动的大型软件。先把一个最简单的 Qt 窗口程序用 windeployqt + Setup 项目做成安装包,跑通一遍,再逐步加入驱动、第三方 DLL、注册表操作。这样出了问题你分得清是哪一环节没做对。
我个人的工作习惯是维护一个打包清单,每次发布前按清单逐项打勾:Release 编译是否通过、windeployqt 是否执行、第三方 DLL 是否齐全、driver 目录是否干净、自定义操作参数是否正确、安装包是否在干净环境验证过。这套清单看起来很傻,但正是它救了我好多次,有一回漏掉了驱动目录里的 .cat 文件,在测试机上驱动始终无法签名验证,对照清单立刻就能定位到是文件缺失。
还有最后一个建议,安装包生成的版本号、厂商名、产品名这些“面子上”的字段一定要认真写,因为这直接影响客户对你的专业感。有些技术上做得很好的团队,结果安装包显示的名字是乱码或者默认的“Setup1”,客户第一印象就差了很多。细节到位,交付才算真的完成。