InstallShield for VC++ 6.0 安装包制作实战:从工程配置到避坑指南
简介InstallShield for VC 6.0 是专为 Microsoft Visual C 6 定制的安装包制作工具面向使用 VC6 开发 Windows 应用程序、需要将 Release 版 EXE 打包发布的开发者。它可直接从 VC6 的 Tools 菜单调用 InstallShield Wizard省去单独配置工程与脚本的麻烦适合刚接触安装包制作、希望快速生成标准安装向导的初中级开发者。资源包共 27 个文件约 10.04MB包含 setup.exe、_isdel.exe 等可执行程序_sys1.cab、_user1.cab、data1.cab 等安装数据压缩包setup.ins、setup.lid、setup.ini 等安装脚本与配置以及 dll、dat、htm、gif、bmp 等运行库、说明文档与界面素材覆盖安装向导运行所需的完整组件。目前已有 1174 人学习下载。借助该工具读者可把调试完成的程序快速封装为带界面、带卸载与注册表写入的安装包直接用于项目交付或软件分发省去手工编写安装脚本的环节。1. Installshield for VC 6.0 安装包制作工具老 IDE 的最后一公里手里维护着一套 VC 6.0 编译出来的 MFC 程序代码能跑、功能稳定客户现场却卡在“怎么装”这一步——这是很多工控、医疗设备、老产线软件维护者共同的处境。Installshield for VC 6.0 安装包制作工具说的就是当年随 Visual C 6.0 一起分发的那套 InstallShield 5.x/6.x 版本它能把编译出来的 exe、dll、ocx、ini 打包成一个带向导界面、能写注册表、能注册 COM 组件、能判断系统环境的 setup.exe。今天还在用它的人多半不是怀旧而是新工具链装不进那台只能跑 XP 或 Win7 的现场机器。这篇笔记按“它到底能干什么 → 工程怎么建 → 脚本怎么改 → 坑在哪 → 怎么验证”的顺序讲目标是让你照着能把一个 VC 6.0 的 MFC 工程打成可交付的安装包。2. InstallShield 5.x 工程结构与 VC 6.0 的衔接方式2.1 为什么老项目还在用这套组合VC 6.0 生成的程序有个绕不开的特征它依赖 mfc42.dll、msvcrt.dll、msvcp60.dll 这一批运行库而且很多老工程用的是 MFC 静态链接之外的动态链接方式目标机器上没装对应运行库就直接报“找不到 mfc42.dll”。InstallShield 5.x 的价值在于它自带一套运行库检测和分发机制能在安装阶段把 VC 运行库一起铺到系统目录还能通过Dependency Walker式的扫描把工程依赖的 dll 自动列进安装清单。另一个现实原因是 COM 组件注册。VC 6.0 时代大量功能靠 ocx 和 dll 实现这些组件必须在安装时用regsvr32注册否则程序启动就报“类未注册”。InstallShield 的Self-Registration机制能在文件拷贝完成后自动调用注册逻辑比手写批处理可靠得多。常见做法是在工程里把 ocx 标记为 self-registered安装脚本里不用额外写注册命令。还有一点是安装界面。老项目的交付对象往往是产线工人或医院设备科他们对“解压到某个目录再双击 exe”这种交付方式接受度低需要一个带“下一步”的向导。InstallShield 5.x 的默认模板就能生成这种界面改改公司名和 logo 就能用不需要额外写 UI 代码。2.2 工程目录里每个文件管什么一个典型的 InstallShield 5.x 工程目录长这样理解每个文件的职责是改脚本的前提文件/目录作用改它的场景Setup.rul主安装脚本InstallScript 语言加自定义检测、改安装流程*.ipr工程文件记录文件分组和快捷方式增删要打包的文件File Groups文件分组定义如AppExecutables把新 dll 归到对应组Components组件定义决定哪些文件一起装拆分主程序和帮助文档Setup.ini安装初始化参数改产品名、版本号、默认路径Language多语言资源加中文界面字符串Setup.rul是核心它用的是 InstallScript 语言语法接近 C但有自己的事件函数OnBegin、OnFirstUIBefore、OnMoving、OnEnd。VC 6.0 工程编译出来的文件不会自动进安装包需要在File Groups里手动添加或通过Link方式关联。我一般会把主 exe 和核心 dll 放一个组把 ocx 单独放一个组并勾选 self-registered把配置 ini 放第三个组安装时按组控制覆盖策略。2.3 从 VC 6.0 工程到安装包的最小操作链假设你有一个编译好的 MFC 工程输出目录是Release里面有MainApp.exe、Core.dll、Grid.ocx、config.ini。下面是从零建一个安装工程的步骤。第一步打开 InstallShield 5.x 的Project Wizard选Standard Setup产品名填你的软件名公司名填客户单位版本号按实际填。向导会问是否允许用户改安装路径老项目一般选“允许”因为现场机器盘符不统一。第二步在File Groups面板右键新建三个组AppBin、AppOcx、AppConfig。把MainApp.exe和Core.dll拖进AppBinGrid.ocx拖进AppOcxconfig.ini拖进AppConfig。第三步选中Grid.ocx在属性面板勾选Self-Registered。这一步等价于告诉安装程序拷贝完这个文件后自动调regsvr32。第四步在Components面板新建一个组件MainComponent把三个文件组都挂进去。如果帮助文档要单独装就再建一个组件。第五步打开Setup.rul在OnFirstUIBefore里加一段检测如果目标机器已经装了更高版本提示用户先卸载。InstallScript 里用RegDBGetKeyValueEx读注册表版本号用MessageBox弹提示。// Setup.rul 片段检测已安装版本 function OnFirstUIBefore() NUMBER nResult; STRING szVersion; begin // 读取注册表中已安装版本 RegDBSetDefaultRoot(HKEY_LOCAL_MACHINE); nResult RegDBGetKeyValueEx( SOFTWARE\\MyCompany\\MainApp, Version, nType, szVersion, nSize ); if (nResult 0) then // 已安装过比较版本 if (szVersion 2.0.0) then MessageBox(检测到已安装更高版本请先卸载。, SEVERE); abort; endif; endif; // 继续默认安装界面 return 0; end;这段脚本的逻辑是先设注册表根为HKEY_LOCAL_MACHINE读SOFTWARE\MyCompany\MainApp下的Version值。如果读到了且大于等于当前要装的版本就弹框并中止安装。参数说明RegDBGetKeyValueEx的第三个参数是类型第四个是接收值的字符串变量第五个是缓冲区大小。注意 InstallScript 的字符串比较是按字典序版本号最好用固定位数如2.0.0和1.9.9避免10.0被当成小于9.0。第六步编译安装工程。InstallShield 会生成setup.exe和一堆.cab文件。如果选了Single Executable就只出一个 exe但体积会大一些。老项目交付一般选单文件方便拷贝。3. 脚本里必须改的四个地方和对应参数3.1 安装路径默认值与 Program Files 判断InstallShield 默认把路径设成C:\Program Files\公司名\产品名但 XP 和 Win7 的 Program Files 路径可能不同32 位和 64 位系统也不一样。常见做法是在OnFirstUIBefore里用GetSystemInfo判断系统类型再拼路径。// 根据系统类型设置默认安装路径 function OnFirstUIBefore() STRING szDefaultPath; NUMBER nType; begin GetSystemInfo(OS_TYPE, nType); if (nType OS_64BIT) then szDefaultPath C:\\Program Files (x86)\\MyCompany\\MainApp; else szDefaultPath C:\\Program Files\\MyCompany\\MainApp; endif; // 把默认路径写入安装界面 SetInstallDir(szDefaultPath); return 0; end;GetSystemInfo的第一个参数OS_TYPE返回系统类型OS_64BIT是常量。SetInstallDir把路径传给安装向导的路径选择页。注意 InstallScript 里反斜杠要写两个字符串拼接用。如果客户现场有绿色版需求可以把默认路径改成D:\MainApp但要在文档里写清楚。3.2 注册表写入与卸载信息登记安装程序不写卸载信息控制面板里就看不到你的软件客户想卸载只能手动删目录。InstallShield 5.x 在OnEnd里可以写注册表把卸载串登记到Uninstall键下。// 写入卸载信息 function OnEnd() STRING szUninstall; STRING szInstallDir; begin // 获取安装目录 szInstallDir TARGETDIR; // 拼卸载命令 szUninstall szInstallDir ^ setup.exe /uninstall; RegDBSetDefaultRoot(HKEY_LOCAL_MACHINE); RegDBSetKeyValueEx( SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MainApp, DisplayName, REGDB_STRING, MainApp 2.0, -1 ); RegDBSetKeyValueEx( SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MainApp, UninstallString, REGDB_STRING, szUninstall, -1 ); return 0; end;TARGETDIR是 InstallScript 的内置变量保存用户选的安装目录。^是字符串拼接符和 C 的不同。RegDBSetKeyValueEx的最后一个参数-1表示字符串长度自动计算。注意UninstallString指向的setup.exe必须在安装目录里存在所以打包时要把setup.exe本身也放进安装文件否则卸载会找不到程序。3.3 运行库检测与 VC 6.0 依赖分发VC 6.0 程序依赖的mfc42.dll、msvcrt.dll、msvcp60.dll在目标机器上不一定有。InstallShield 5.x 自带一个Redistributable机制但老版本的清单可能不全。我一般手动把这三个 dll 放进AppBin组然后在OnMoving里检测系统目录是否已有更高版本。// 检测系统目录运行库版本 function OnMoving() STRING szSysDir; STRING szDllPath; NUMBER nResult; begin szSysDir GetSystemDir(); szDllPath szSysDir ^ \\mfc42.dll; nResult FileExists(szDllPath); if (nResult 0) then // 系统没有从安装包拷贝 CopyFile(TARGETDIR ^ \\mfc42.dll, szSysDir); endif; return 0; end;GetSystemDir返回系统目录XP 下是C:\Windows\System32。FileExists返回 0 表示不存在。CopyFile把安装目录里的 dll 拷到系统目录。注意这个操作需要管理员权限如果客户是普通用户账户拷贝会失败。替代方案是把 dll 放在程序同目录但 VC 6.0 的 MFC 程序默认从系统目录加载同目录加载需要改 manifest 或注册表老项目一般不折腾直接要求管理员安装。3.4 快捷方式与开始菜单项安装完不建快捷方式用户找不到程序。InstallShield 5.x 在OnEnd里用CreateShortCut建桌面和开始菜单快捷方式。// 创建快捷方式 function OnEnd() STRING szExePath; STRING szShortcut; begin szExePath TARGETDIR ^ \\MainApp.exe; // 桌面快捷方式 szShortcut C:\\Documents and Settings\\All Users\\Desktop\\MainApp.lnk; CreateShortCut(szExePath, szShortcut, , , , 0); // 开始菜单 szShortcut C:\\Documents and Settings\\All Users\\Start Menu\\Programs\\MainApp.lnk; CreateShortCut(szExePath, szShortcut, , , , 0); return 0; end;CreateShortCut的参数依次是目标 exe、快捷方式路径、参数、工作目录、图标路径、图标索引。All Users目录在 XP 下是C:\Documents and Settings\All UsersWin7 下是C:\ProgramData所以这段脚本在 Win7 上会失败。更稳的做法是用GetFolderPath获取系统文件夹路径但 InstallShield 5.x 的GetFolderPath支持有限常见做法是判断系统版本后拼路径。4. 避坑InstallShield 5.x 在 VC 6.0 项目里的五个翻车点4.1 安装包在 Win7 上提示“不是有效的 Win32 应用程序”现象在 XP 上编译好的setup.exe拷到 Win7 上双击报错。原因InstallShield 5.x 生成的安装引擎是 16 位或早期 32 位Win7 64 位不兼容。解决在 InstallShield 工程设置里把Setup Launcher改成 32 位模式或者用 InstallShield 6.x 以上版本重新编译。如果客户只有 Win7 64 位建议直接换 InstallShield 2010 之后的版本但那样就不叫“for VC 6.0”了需要重新做工程。4.2 ocx 注册失败程序启动报“类未注册”现象安装过程没报错但程序启动时弹“Class not registered”。原因Self-Registered勾选了但 ocx 依赖的其他 dll 没一起注册或者注册时权限不够。解决先用regsvr32手动注册一次看报什么错。如果是依赖缺失用Dependency Walker打开 ocx 看缺哪个 dll把缺失的 dll 也放进安装包。如果是权限问题在OnEnd里用LaunchAppAndWait显式调regsvr32并加/s静默参数。4.3 安装路径含中文或空格导致脚本失败现象用户把程序装到D:\我的软件安装完成但快捷方式指向错误。原因InstallScript 对中文路径处理不好TARGETDIR变量里的中文可能变成乱码。解决在OnFirstUIBefore里检测路径是否含非 ASCII 字符如果有就提示用户换路径。或者干脆把默认路径设成纯英文并在文档里写明“不要装到中文目录”。4.4 卸载时残留注册表和文件现象控制面板卸载后注册表里还有SOFTWARE\MyCompany\MainApp安装目录里还有config.ini。原因InstallShield 只删除自己记录的文件用户后来生成的配置文件不在清单里。解决在OnUninstall事件里手动删注册表键和残留目录。InstallScript 用RegDBDeleteKey删键用DeleteDir删目录但DeleteDir只能删空目录需要先DeleteFile删文件。4.5 编译出的 setup.exe 体积过大现象一个 5MB 的程序安装包 50MB。原因InstallShield 默认把运行库、多语言资源全打进去了。解决在File Groups里去掉不需要的语言包在Setup.ini里把Compression设成High在Media设置里选Single Executable并勾选Compress。如果还是大检查是不是把Debug目录的文件也打进去了只打Release目录。5. 验证安装包是否可交付的三个硬指标5.1 在干净虚拟机上跑一遍完整安装卸载装完系统后不打任何补丁直接跑setup.exe看能不能装完、程序能不能启动、卸载后目录和注册表是否干净。这一步能暴露 80% 的依赖问题。我一般用 VMware 建一个 XP SP3 快照每次改完安装脚本就恢复快照重跑一遍。注意虚拟机要设成和客户现场一样的系统版本和位数XP 32 位和 Win7 32 位的表现可能不同。5.2 用 Process Monitor 看安装过程写了哪些注册表安装时开着 Process Monitor过滤RegSetValue和CreateFile看安装程序到底写了哪些键、拷了哪些文件。如果发现写了不该写的键比如覆盖了系统运行库的版本号就要在脚本里加判断。这个工具比看 InstallShield 日志直观适合排查“装完系统变慢”这类玄学问题。5.3 检查安装日志里的错误码InstallShield 会在%TEMP%下生成Setup.log里面记录了每一步的结果。安装失败时先看这个日志搜Error和Fail。常见的错误码-1是文件拷贝失败-2是注册表写入失败-3是权限不足。日志里还会记录TARGETDIR的实际值如果路径不对说明SetInstallDir没生效。5.4 一个我常用的版本号自增技巧每次发版手动改Setup.ini里的版本号容易忘我习惯在 VC 6.0 工程里加一个version.h用宏定义版本号然后在 InstallShield 的Setup.rul里用#include引入这个头文件。InstallScript 支持#include但路径要用相对路径或绝对路径。这样编译安装包时版本号自动和程序一致减少“装完发现版本不对”的返工。// version.h 放在 VC 工程和 InstallShield 工程都能找到的目录 #define APP_VERSION 2.0.3 #define APP_NAME MainApp// Setup.rul 里引用 #include ..\\..\\version.h function OnBegin() STRING szMsg; begin szMsg APP_NAME ^ ^ APP_VERSION ^ 安装程序; SetTitle(szMsg, 0); return 0; end;SetTitle设置安装向导的标题栏文字。#include的路径是相对于Setup.rul所在目录的如果两个工程不在同一目录树就用绝对路径但绝对路径换机器会失效所以最好把version.h放在两个工程都能访问的公共目录比如D:\Project\Common。这套组合我用了很多年最大的体会是InstallShield 5.x 的脚本能力足够应付 VC 6.0 项目的交付但它的坑集中在系统兼容性和权限上每次换客户环境都要重新验证一遍。别信“一次做好到处能装”老 IDE 的安装包没有银弹只有快照和日志。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

DeepSeek Harness桌面端:本地代理与会话管理的安全实践

DeepSeek Harness桌面端:本地代理与会话管理的安全实践

1. 为什么我会需要一个 DeepSeek 桌面端 先交代下背景。我一直是 DeepSeek 的深度用户,日常写代码、做文档、跑数据分析,大部分时间都泡在浏览器里跟它对话。用久了之后,痛点其实非常明确:浏览器标签页一多,会话就找不…

2026/10/13 8:58:45 阅读更多 →
学术评价体系外的多元发展路径探索

学术评价体系外的多元发展路径探索

1. 学术生涯的另一种可能性"我30多年学术生涯中,既没中过什么课题,也没中过什么项目"——这句话乍听像是失败者的自白,实则揭示了学术界一个鲜少被讨论的真相:在传统评价体系之外,存在着另一种学术生存方式。…

2026/10/13 8:57:36 阅读更多 →
SpringBoot网上团购系统毕设全解析:表设计、核心代码与答辩攻略

SpringBoot网上团购系统毕设全解析:表设计、核心代码与答辩攻略

每年到了二三月份,我的私信里就会被同一类问题塞满:"学长,毕设没思路怎么办""有没有现成的SpringBoot项目,能跑起来就行""团购系统的源码能不能给我一份"。说句实话,计算机毕业设计这个…

2026/10/13 8:57:36 阅读更多 →

最新新闻

机器学习评估体系:从泛化误差到业务指标的完整实践

机器学习评估体系:从泛化误差到业务指标的完整实践

1. 这不是背书,是建模前的“体检清单”——为什么第2章决定你80%的模型成败“西瓜书”第二章《模型的评估与选择》,表面看是教你怎么算准确率、画个ROC曲线、调个交叉验证的k值,但实操中我带过几十个刚入门的项目组,发现一个扎心事…

2026/10/13 9:41:42 阅读更多 →
矩阵实编码遗传算法在电力系统机组组合优化中的应用

矩阵实编码遗传算法在电力系统机组组合优化中的应用

## 1. 项目背景与核心价值机组组合问题(Unit Commitment, UC)是电力系统调度中的经典优化难题,需要在满足负荷需求的前提下,确定各发电机组的启停状态和出力分配,使总运行成本最小化。传统数学规划方法(如混…

2026/10/13 9:41:42 阅读更多 →
电信机顶盒E900V22D硬件解析与性能优化指南

电信机顶盒E900V22D硬件解析与性能优化指南

1. 电信机顶盒E900V22D硬件解析作为一款主流运营商定制设备,E900V22D机顶盒的硬件架构直接决定了其性能表现和功能边界。拆解实机可见,这款设备采用高度集成化的主板设计,PCB板尺寸仅为128cm,却承载了完整的媒体处理功能模块。1.1…

2026/10/13 9:41:42 阅读更多 →
SQL中AVG()的四大陷阱:NULL、0值、粒度与语义

SQL中AVG()的四大陷阱:NULL、0值、粒度与语义

1. 项目概述:平均值不是“除一下”就完事的——SQL里最常被低估的统计陷阱“怎么算平均值?”刚接触SQL的新手常以为就是AVG()函数一贴,结果跑出来数据和Excel对不上,或者业务方突然质疑:“上个月人均消费3800&#xff…

2026/10/13 9:41:42 阅读更多 →
智慧港口整体解决方案:码头流程再造与自动化落地实战

智慧港口整体解决方案:码头流程再造与自动化落地实战

简介:《智慧港口整体解决方案》是一份面向港口管理部门、航运企业及智慧交通领域从业者的专题方案文档,聚焦如何借助新一代感知、传输与应用技术,实现对码头、船舶、货物、重大危险源及航管航运等要素的全面感知、有效传输与按需定制服务。方…

2026/10/13 9:41:42 阅读更多 →
艾里函数:临界过渡建模的核心数学工具

艾里函数:临界过渡建模的核心数学工具

1. 为什么艾里函数不是“空气里的函数”,而是物理建模的隐形骨架很多人第一次看到“Airy函数”这个名字,下意识会联想到“airy”(空气的、轻盈的),甚至以为是某种和气流或浮力相关的数学工具。我刚接触这个概念时也这么…

2026/10/13 9:40:38 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目,我最大的感受是,大部分坑不是出在技术前沿,而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节,最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了,很难不碰到舵机控制这道坎。做智能小车要转方向,做机械臂要抬关节,做云台要偏航俯仰,背后都是同一个东西在干活:舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”?——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台?或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜?又或者,在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 21:05:09 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 14:48:49 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →