news 2026/5/23 7:26:56

ESP32/ESP8266固件备份全攻略:esptool与flash_download_tool实战详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ESP32/ESP8266固件备份全攻略:esptool与flash_download_tool实战详解

1. 项目概述:为什么我们需要备份ESP32/8266的固件?

在嵌入式开发或者物联网项目中,ESP32和ESP8266这两款芯片的应用已经非常普遍了。无论是做智能家居、数据采集还是各种DIY小玩意儿,我们经常会在上面编写和烧录固件。但不知道你有没有遇到过这种情况:一个项目运行得好好的,突然想修改一下功能,结果把新代码烧进去后,发现还不如原来的稳定,或者某个关键功能失效了。更糟糕的是,你发现手头根本没有旧固件的源代码,或者源代码因为各种原因(比如换了电脑、项目文件夹误删)找不到了。这时候,如果能把芯片里正在运行的、完好的固件程序“读”出来,备份一份,那简直就是救命稻草。

这个“读出来”的过程,就是我们常说的固件备份或固件提取。它不仅仅是简单的文件拷贝,因为固件是二进制代码,直接存储在芯片的Flash存储器里。我们需要通过特定的工具和协议,与芯片的引导程序(Bootloader)通信,将整个Flash存储区域的内容,按字节读取出来,保存成一个.bin文件。这个.bin文件,就是芯片里运行的程序、数据、配置信息等一切内容的完整镜像。

今天,我就结合自己多年的折腾经验,详细拆解两种最主流、最可靠的ESP固件备份方法:使用官方的命令行工具esptool.py,以及使用图形化工具flash_download_tool。我会深入讲解每一步操作的原理、注意事项,并分享一些官方文档里不会写的“坑”和技巧,让你不仅能成功备份,更能理解背后的逻辑,做到举一反三。

2. 核心工具解析:esptool与flash_download_tool

在开始动手之前,我们得先搞清楚手里这两把“瑞士军刀”到底是什么,以及它们各自适合什么场景。盲目使用工具,往往事倍功半。

2.1 esptool.py:命令行下的终极控制

esptool.py是乐鑫(Espressif)官方开源维护的一个Python命令行工具。它的地位,相当于ESP芯片的“底层手术刀”。几乎所有与ESP芯片Flash存储器相关的底层操作,最终都是由它或它的封装版本来完成的。

它的核心工作原理是这样的:ESP芯片上电后,首先运行的不是你的应用程序,而是一段固化在ROM中的引导加载程序(Bootloader)。esptool.py通过电脑的串口(UART,也就是我们常说的COM口)与这个Bootloader建立通信。双方遵循一套特定的串行协议(早期是SLIP,后来是改进的ESP-TOUCH协议),esptool.py发送各种指令(比如“读内存”、“写内存”、“擦除扇区”),Bootloader接收并执行,然后将结果返回。整个过程中,esptool.py扮演了一个“指挥官”的角色。

为什么开发者都应该了解它?

  1. 它是基石:无论你用的是Arduino IDE、PlatformIO还是乐鑫官方的ESP-IDF,当你点击“上传”按钮时,这些集成开发环境(IDE)都是在后台默默地调用了esptool.py。了解它,就是了解烧录过程的本质。
  2. 灵活性极高:命令行工具意味着你可以精确控制每一个参数,编写脚本实现自动化备份、批量烧录等高级操作,这是图形化工具难以比拟的。
  3. 故障排查的利器:当图形化工具烧录失败,报出一些模棱两可的错误时,直接用esptool.py执行相同操作,往往能获得更详细、更底层的错误信息,帮助你快速定位是线缆问题、端口问题还是固件本身的问题。

注意esptool.py是一个Python脚本,所以你的电脑上必须安装有Python环境(建议Python 3.7或更高版本)。这是使用它的唯一前提。

2.2 flash_download_tool:图形化界面的一键操作

如果说esptool.py是给工程师和高级玩家用的手术刀,那么flash_download_tool就是给所有用户准备的“一键备份/恢复”按钮。它同样是乐鑫官方提供的工具,但以图形化窗口程序(GUI)的形式呈现。

它的设计初衷是简化操作:这个工具将esptool.py的常用功能(如读取芯片信息、备份Flash、烧录固件)封装成了点击按钮和填写表单。你不需要记忆复杂的命令参数,只需要选择串口号、设置文件路径、点击“Start”即可。对于不熟悉命令行的用户,或者需要快速进行简单操作的场景,它非常友好。

它的内在依然是esptool:本质上,flash_download_toolesptool核心功能的一个图形化外壳。它在后台调用的通信库和协议与esptool.py是同源的。因此,通过它读取出来的固件文件,与用esptool.py读出来的,在二进制层面是完全一致的。

两种工具的选择策略:

  • 新手入门、快速备份/烧录单个固件:优先选择flash_download_tool。界面直观,不易出错。
  • 自动化脚本、批量处理、复杂分区表烧录、深度调试:必须使用esptool.py
  • 学习和理解底层过程:建议从esptool.py入手,它能让你对ESP的存储架构有更清晰的认识。

在实际项目中,我通常是两者结合使用。用flash_download_tool快速验证芯片和连接是否正常,用esptool.py编写部署脚本。下面,我们就进入实战环节。

3. 环境准备与连接确认

磨刀不误砍柴工。无论用哪种方法,第一步都是确保你的“工作台”是就绪的。

3.1 硬件连接:不仅仅是插上线

你需要准备一块ESP32或ESP8266开发板(如NodeMCU、ESP32-DevKitC等),以及一条可靠的USB数据线。

这里有一个至关重要的细节:很多便宜的USB线只能供电,不能传输数据!你一定遇到过电脑识别不到串口的情况,很可能就是线的问题。务必使用一条已知良好的、支持数据传输的USB线。对于ESP8266,通常使用Micro-USB线;对于较新的ESP32型号,可能是Type-C接口。

将开发板通过USB线连接到电脑。连接成功后,开发板上的电源指示灯(通常是红色或蓝色)应该会亮起。

3.2 驱动安装:让电脑认识你的芯片

ESP开发板内部集成了一个USB转串口芯片(常见的有CH340、CP2102、FT232等)。Windows系统通常不会自动安装这些芯片的驱动。

如何检查和安装驱动:

  1. 右键点击“此电脑” -> “管理” -> “设备管理器”。
  2. 连接开发板后,查看“端口(COM和LPT)”一项。如果看到带有“CH340”、“CP2102”或“USB Serial Port”字样的设备,并且前面没有黄色的感叹号,说明驱动已安装成功。请记下后面的COM口号(如COM3、COM4、COM218),后续命令中会用到。
  3. 如果看到“未知设备”或有黄色感叹号,你需要根据开发板型号,去制造商官网或芯片供应商官网(如Silicon Labs官网找CP2102驱动,沁恒官网找CH340驱动)下载对应的驱动程序并安装。

在Linux或macOS下:通常系统已内置驱动,连接后设备会显示为/dev/ttyUSB0/dev/tty.SLAB_USBtoUART等形式。你需要有权限访问该设备(通常需要将用户加入dialout组)。

3.3 软件工具准备

对于使用 esptool.py:

  1. 安装Python:从 Python官网 下载并安装。安装时务必勾选“Add Python to PATH”。
  2. 安装esptool:打开命令行(Windows下是CMD或PowerShell,macOS/Linux下是Terminal),输入以下命令:
    pip install esptool
    安装完成后,输入esptool.py versionesptool version(新版本)检查是否安装成功。

对于使用 flash_download_tool:

  1. 从乐鑫官方GitHub仓库或通过搜索引擎找到“乐鑫flash下载工具”进行下载。下载后解压,无需安装,直接运行可执行文件(如flash_download_tool_xxx.exe)即可。

环境就绪,连接正常,我们就可以开始最激动人心的部分——把芯片里的“灵魂”读取出来了。

4. 方法一:使用esptool.py命令行备份固件

命令行操作看似复杂,但步骤清晰,可重复性强。我们一步一步来。

4.1 第一步:确认连接与芯片信息

在动手读取整个Flash之前,我们先进行一次“握手”测试,确认工具能和芯片正常对话,并获取关键信息。

打开命令行,进入你打算存放备份文件的目录(方便后续操作),然后输入以下命令:

esptool.py --port COM218 flash_id

请将COM218替换为你自己在设备管理器中查看到的实际端口号。在Linux/macOS下,可能是/dev/ttyUSB0

这个命令做了两件重要的事:

  1. 测试通信:如果命令成功执行,没有报“Failed to connect”之类的错误,说明串口连接、驱动、波特率(使用默认)都是正常的。
  2. 获取Flash信息:命令会返回芯片的制造商ID(Manufacturer)和设备ID(Device),以及最重要的——Flash容量大小

执行成功的输出会类似这样:

Detecting chip type... ESP32 Chip is ESP32-D0WDQ6 (revision 1) Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None Crystal is 40MHz MAC: xx:xx:xx:xx:xx:xx Uploading stub... Running stub... Stub running... Manufacturer: c8 Device: 4016 Detected flash size: 16MB Hard resetting via RTS pin...

请死死盯住Detected flash size: 16MB这一行。这里的16MB就是你的芯片Flash总容量,它是我们后续备份命令的核心参数。常见的还有4MB, 8MB。记下这个值,我们马上要用。

4.2 第二步:理解Flash地址与容量参数

这是备份操作中最容易出错的一步。我们需要在命令中告诉esptool.py:“请从Flash的哪个位置开始读,一共读多少字节。”

  • 起始地址(Start Address):对于完整备份整个Flash内容,这个值永远是0。因为Flash的存储空间是从地址0x00000000开始的。
  • 读取长度(Size):这里要填的就是整个Flash的大小。但注意,命令行参数需要的是字节数,而不是“16MB”这样的字符串。

容量换算关系:

  • 1MB = 1024 KB = 1024 * 1024 字节 = 1,048,576 字节
  • 16MB = 16 * 1024 * 1024 字节 = 16,777,216 字节

在计算机中,我们常用十六进制(Hex)来表示地址和大小,因为它更简洁,与硬件描述更匹配。

  • 16MB = 0x1000000 字节 (这是十六进制表示)
  • 8MB = 0x800000 字节
  • 4MB = 0x400000 字节
  • 2MB = 0x200000 字节

请根据你上一步用flash_id检测到的容量,选择对应的十六进制值。如果你检测到是4MB,就在命令里用0x400000

4.3 第三步:执行备份命令

现在,组装我们的备份命令。命令格式如下:

esptool.py --port 你的端口号 --baud 波特率 read_flash 起始地址 长度 保存的文件路径

一个具体的、备份16MB Flash的例子:

esptool.py -p COM218 -b 921600 read_flash 0 0x1000000 “C:UsersYourNameDesktopesp_backup.bin”

让我们拆解这个命令的每个部分:

  • -p COM218:-p--port的缩写,指定串口端口。
  • -b 921600:-b--baud的缩写,指定通信波特率。921600是一个较高的波特率,可以加快读取速度。如果连接不稳定导致出错,可以尝试降低到460800115200
  • read_flash: 这是核心指令,告诉工具要执行“读Flash”操作。
  • 0: 起始地址,从0开始。
  • 0x1000000: 要读取的长度,这里是16MB的十六进制表示。
  • “C:...backup.bin”: 备份文件保存的完整路径和文件名。路径可以自己指定,但文件名不需要事先创建,工具会自己生成这个文件。

执行过程与解读:输入命令,按下回车。你会看到类似下面的输出:

Connecting... Detecting chip type... ESP32 Chip is ESP32-D0WDQ6 (revision 1) Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None Crystal is 40MHz MAC: xx:xx:xx:xx:xx:xx Uploading stub... Running stub... Stub running... Reading flash (0%)... Reading flash (100%)... Read 16777216 bytes at 0x0 in 29.1 seconds (4.6 Mbit/s)... Hard resetting via RTS pin...

这个过程可能会持续几十秒到几分钟,取决于Flash大小和波特率。你会看到一个进度百分比。当显示“Read … bytes … in … seconds”时,就表示备份完成了!去你指定的路径下,就能找到那个宝贵的.bin文件。

4.4 第四步:验证备份文件(可选但推荐)

如何确认我们备份出来的文件是完整可用的呢?一个直接的方法就是把它再烧录回去,或者烧录到另一块同型号的芯片里,看功能是否正常。

烧录单个备份文件的命令:

esptool.py -p COM218 -b 460800 write_flash 0 “C:UsersYourNameDesktopesp_backup.bin”

这个命令和读取很像,只是把read_flash换成了write_flash。它会把backup.bin文件的内容,从Flash地址0开始,完整地写回去。

重要心得:烧录前的擦除在烧录新固件(尤其是完整覆盖的备份文件)之前,强烈建议先擦除整个Flash。因为Flash的写入机制是只能将1写成0,不能直接将0写成1。擦除操作会将整个扇区恢复为全1(0xFF)状态,确保写入过程干净顺利。 擦除命令非常简单:

esptool.py -p COM218 erase_flash

执行擦除后,再执行上面的write_flash命令。

5. 方法二:使用flash_download_tool图形化备份固件

对于更喜欢点击鼠标的用户,图形化工具是更友好的选择。它的逻辑和命令行是一致的,只是换成了界面操作。

5.1 工具启动与芯片选择

  1. 解压并运行flash_download_tool.exe
  2. 首先会弹出一个芯片选择窗口。这里非常关键,一定要选对!
    • 对于ESP8266,选择ESP8266 DownloadTool
    • 对于ESP32,选择ESP32 DownloadTool
    • 对于ESP32-C3/S2/S3等衍生型号,选择ESP32 DownloadTool(通常通用,如果不行,请查找对应型号的专用版本)。 选错型号会导致连接失败或操作异常。

5.2 界面配置与备份操作

进入主界面后,你会看到多个标签页。我们主要关注SPIDownload这个页签。

  1. 确认连接:在右上角的COM下拉框中,选择你的ESP开发板对应的串口号。波特率(BAUD)可以设置得高一些,比如921600,以加快速度。
  2. 读取芯片信息:在点击任何按钮前,先点击界面上的Read MacChipInfo按钮(不同版本位置可能略有不同)。如果成功读取到芯片的MAC地址和型号信息,说明连接正常。这一步等同于命令行的flash_id
  3. 配置备份参数
    • StartAddr(Hex): 起始地址,填0x0
    • Size(Hex): Flash大小。这里需要手动输入十六进制值。根据之前检测到的容量,如果是16MB,就填0x1000000;4MB就填0x400000这是最容易填错的地方!不要直接填“16M”。
    • File Path: 点击后面的按钮,选择备份文件要保存的路径,并输入一个文件名,例如my_backup.bin
  4. 执行备份:确保操作选项选择了Read(读取)。然后,勇敢地点击右下角的START按钮。
  5. 等待完成:此时,进度条会开始走动,下方的日志框会显示读取进度和速度。当进度条走满,日志显示“Finish”或“Read completed”时,备份就完成了。备份好的.bin文件会自动生成在你指定的路径下。

5.3 图形化工具的烧录验证

验证同样简单。我们就在这个工具里把刚备份的文件烧录回去。

  1. 切换模式:将操作选项从Read改为Write(写入/烧录)。
  2. 选择文件:在File Path区域,点击,选择你刚刚备份成功的my_backup.bin文件。
  3. 设置地址:确保后面的StartAddr(Hex)0x0。工具通常会自动填充。
  4. 执行烧录:再次点击START按钮。工具会先将文件内容缓存,然后擦除对应区域(如果需要),最后写入。看到进度条完成和“Finish”日志,烧录就结束了。

此时,给芯片重新上电,它就应该运行着和备份前一模一样的程序了。

6. 高级应用与疑难排错

掌握了基本操作后,我们来看看一些更深入的应用场景和常见问题的解决方法。

6.1 备份特定部分与多文件烧录

有时我们不需要备份整个16MB的Flash,可能只关心应用程序本身(比如从0x10000地址开始)。esptool.py可以轻松做到:

# 假设应用程序分区从0x10000开始,大小是1MB (0x100000字节) esptool.py -p COM3 read_flash 0x10000 0x100000 app_backup.bin

更常见的是多文件烧录。一个完整的ESP32固件通常由多个.bin文件组成,烧录到不同的地址:

  • bootloader.bin-> 地址0x1000
  • partitions.bin-> 地址0x8000
  • app.bin(你的主程序) -> 地址0x10000

使用esptool.py可以一条命令完成:

esptool.py -p COM3 -b 460800 write_flash 0x1000 bootloader.bin 0x8000 partitions.bin 0x10000 app.bin

注意,这里将地址和文件路径成对列出即可。这种灵活性是图形化工具较难实现的。

6.2 常见错误与解决方案

在实际操作中,你几乎一定会遇到下面这些问题。别慌,都有解决办法。

问题1:连接失败(Failed to connect to ESP32/8266)

  • 症状:执行任何命令都立即报错,无法连接。
  • 排查步骤
    1. 检查线缆和端口:换一条数据线,确认设备管理器中的COM口存在且无感叹号。
    2. 检查Boot模式:ESP芯片必须进入“下载模式”才能被esptool识别。通常需要将GPIO0引脚拉低(接地)后复位或上电。很多开发板通过一个“FLASH”或“DOWNLOAD”按钮自动实现了这个功能,按下按钮再上电,或者先按住按钮再上电,然后松开。这是最容易被忽略的一步!
    3. 降低波特率:尝试将-b参数改为115200
    4. 关闭占用程序:确保Arduino IDE、PlatformIO、串口监视器等任何可能占用该COM口的软件都已关闭。

问题2:读取/写入超时或校验错误

  • 症状:操作中途失败,提示超时(Timeout)或数据校验失败(Checksum fail)。
  • 排查步骤
    1. 降低波特率:高波特率对线缆质量和信号完整性要求高。将波特率从921600降至460800115200再试。
    2. 检查电源:使用外部电源为开发板供电,或者换一个USB口(最好使用主板后置的USB口),避免因USB供电不足导致芯片工作不稳定。
    3. 缩短线缆:使用更短、质量更好的USB线。

问题3:备份出的文件烧录后不运行

  • 症状:备份和烧录过程都成功,但芯片重新上电后没反应(不启动)。
  • 排查步骤
    1. 确认备份完整性:检查备份文件的大小是否与Flash容量完全一致(如16MB文件应为16,777,216字节)。如果文件大小不对,说明备份过程可能被中断。
    2. 检查烧录地址:确保烧录时起始地址是0x0。如果烧录到了错误地址,程序自然无法从正确位置启动。
    3. 芯片型号匹配:确保备份源芯片和烧录目标芯片的型号、Flash大小完全相同。不同型号的芯片,其Bootloader和内存映射可能有差异。

问题4:flash_download_tool无法识别芯片

  • 症状:在工具里点击Read Mac没反应,或者一直显示“等待上电同步”。
  • 排查步骤
    1. 确认芯片类型选择:再次检查第一步启动时选择的芯片类型是否正确。
    2. 手动进入下载模式:参照问题1的步骤,确保芯片已进入下载模式。
    3. 尝试旧版本工具:有时新版本的工具有兼容性问题,可以尝试下载一个稍旧版本的flash_download_tool

6.3 自动化脚本示例

如果你需要定期备份多个设备,手动操作太麻烦。这里分享一个简单的Windows批处理脚本示例,用于自动备份连接在COM3和COM4上的两个ESP32设备:

@echo off REM 备份COM3上的设备 echo Backing up device on COM3... esptool.py -p COM3 -b 921600 read_flash 0 0x1000000 backup_COM3_%date:~0,4%%date:~5,2%%date:~8,2%.bin if %errorlevel% equ 0 ( echo COM3 backup succeeded. ) else ( echo COM3 backup failed! ) REM 备份COM4上的设备 echo Backing up device on COM4... esptool.py -p COM4 -b 921600 read_flash 0 0x1000000 backup_COM4_%date:~0,4%%date:~5,2%%date:~8,2%.bin if %errorlevel% equ 0 ( echo COM4 backup succeeded. ) else ( echo COM4 backup failed! ) pause

这个脚本会将备份文件以日期命名。你可以根据实际情况修改端口号、Flash大小和保存路径。在Linux/macOS下,可以编写类似的Shell脚本。

7. 安全、伦理与最佳实践

最后,我们必须严肃地讨论一下固件备份的边界问题。这项技术是一把双刃剑。

1. 版权与知识产权你备份的固件,可能是你自己编写的,也可能是公司产品、商业设备或开源项目的一部分。请务必遵守相关的软件许可证(License)和法律法规。对于他人的商业固件,未经明确授权进行备份、复制、分发或逆向工程,很可能侵犯知识产权。这里的知识仅限用于学习、研究你拥有合法权限的固件,或者用于恢复你自己开发的设备。

2. 设备安全从另一个角度看,作为开发者,你也应该意识到你的产品固件有被提取的风险。如果固件中包含敏感信息(如Wi-Fi密码、API密钥、加密私钥),绝对不要以明文形式硬编码在固件中。应该使用非易失性存储(如NVS)、安全芯片(如ESP32的PSRAM加密特性)或在首次配网时由用户输入。对于商业产品,可以考虑使用Flash加密功能,这会使得通过常规方式读取出的Flash内容处于加密状态,无法直接分析。

3. 操作最佳实践

  • 标记与归档:备份好的.bin文件,建议用清晰的名称和日期进行标记(例如SmartSwitch_Firmware_v1.2_20231027.bin),并妥善归档。时间久了,你很可能忘记这个bin文件对应哪个版本的程序。
  • 版本控制:虽然.bin是二进制文件,但可以将其纳入Git等版本控制系统进行管理,至少能记录每次备份的时间点和备注。
  • 验证完整性:重要的备份,在操作完成后,可以计算一下文件的MD5或SHA256校验和,并记录下来。下次烧录前再计算一次,确保文件在存储过程中没有损坏。
  • 环境记录:对于复杂的项目,备份固件时,最好也记录下当时编译该固件所用的开发环境、库版本、编译器版本等。这样在需要基于备份恢复开发时,能快速重建环境。

固件备份是一个极其实用的技能,它不仅是代码的保险绳,也是深入理解嵌入式系统运行机理的窗口。希望这篇超详细的指南,能帮你牢牢掌握这项技能,在开发和调试中更加游刃有余。记住,多动手试错,遇到问题按部就班地排查,你很快就能成为ESP芯片的“读心专家”。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/23 7:23:45

电化学阻抗谱等效电路模型:从核心元件到拟合实战指南

1. 等效电路模型:电化学系统的“翻译官”如果你拆开过一块手机电池或者研究过电化学传感器,可能会好奇,我们如何用一个简单的“电路图”来理解内部复杂的离子穿梭和电子转移?这就是等效电路模型的魅力所在。它就像一个经验丰富的翻…

作者头像 李华
网站建设 2026/5/23 7:23:42

缓存一致性协议的安全挑战与防御机制

1. 缓存一致性协议与安全挑战现代多核处理器通过缓存一致性协议维护共享数据的一致性,其中MESI(Modified/Exclusive/Shared/Invalid)是最经典的实现。当某个核心修改数据时,协议会协调其他核心中对应缓存行的状态变更。例如&#…

作者头像 李华
网站建设 2026/5/23 7:21:26

嵌入式车牌识别实战:V4L2+Qt+云端OCR全链路开发指南

1. 项目概述与核心思路最近在折腾一个嵌入式端的车牌识别项目,核心目标是在一块资源有限的开发板上,通过USB摄像头实时采集图像,然后调用云端OCR服务完成车牌号码的提取,最后将结果实时显示在本地Qt界面上。这个项目听起来像是把好…

作者头像 李华
网站建设 2026/5/23 7:20:13

Linux文件操作实战:find、grep、tar命令组合应用与避坑指南

1. 项目概述:为什么我们需要掌握这些“基础”命令?在Linux世界里混迹,无论是运维、开发还是数据工程师,总绕不开几个高频动作:找文件和动文件。文件找不着,后续操作全是空谈;文件太大或太多&…

作者头像 李华
网站建设 2026/5/23 7:18:02

Windows与Linux跨系统数据传输:从SCP、Rsync到自动化脚本的完整指南

1. 项目概述:为什么我们需要跨系统传输数据?在混合IT环境成为常态的今天,一个典型的开发或运维场景是:你的主力工作机运行着Windows,而你的代码、应用或数据处理任务则部署在远端的Linux服务器上。无论是将本地的配置文…

作者头像 李华
网站建设 2026/5/23 7:18:00

Windows右键菜单终极清理指南:用ContextMenuManager告别杂乱菜单

Windows右键菜单终极清理指南:用ContextMenuManager告别杂乱菜单 【免费下载链接】ContextMenuManager 🖱️ 纯粹的Windows右键菜单管理程序 项目地址: https://gitcode.com/gh_mirrors/co/ContextMenuManager 还在为Windows右键菜单越来越臃肿而…

作者头像 李华