
简介Notepad v8.6.6源代码是一份完整的编辑器源码压缩包面向希望研究Windows桌面应用开发、文本编辑器实现原理的C开发者尤其适合想深入理解Scintilla控件集成、语法高亮机制和插件扩展接口的程序员。压缩包共2000个文件大小约11.48MB以h/hpp/cpp/cxx等C源码为主并结合大量xml、properties、styled/folded等配置文件涵盖词法规则、UI资源、项目工程与脚本工具目录结构清晰便于对照定位与按模块学习。已有877人学习下载。通读源码可以弄清Notepad如何基于Windows API搭建高性能编辑框架掌握Scintilla的调用与扩展方式理解多语言高亮规则定义以及插件管理器的加载通信流程同时从内存优化、大文件处理等实现中借鉴实践技巧适用于教学、二次开发或自研编辑器参考。1. 为什么要盯住 Notepad v8.6.6 这份源码而不是下一个绿色版搜索框里敲下「Notepad v8.6.6源代码」的人通常不是来读书的。一个反直觉的事实是网上热传的 notepad zip 绿色版只是编译产物真正能听你使唤的是那份以 .vcxproj 和 .rc 文件为主的源码包。大多数人先下载绿色版然后发现默认行为改不动——编码猜测逻辑不如意、更新提示关不掉、标签栏交互想调整却无处下手最后都得回到源代码这条路上。你就是那个想动手的人内网分发、给团队统一默认配置或者单纯想把这个老牌编辑器的运行逻辑拆开看明白。这篇笔记从拿到源码开始讲目录结构、工具链、编译命令、三个常见定制点以及五条拿来就能用的踩坑记录。目标是让你不在 “不会编” 和 “改完没生效” 之间反复横跳。2. 从 zip 到源码地图v8.6.6 源码包先认这三层下载不是终点解包之后先分清产物类型。官方发布渠道通常会同时给出安装包、zip 绿色版和源码包三种东西新手最容易混淆的就是前两种zip 绿色版里也有 exe、DLL 和配置文件看起来“很全”但里面没有工程文件也没有任何能改变默认行为的入口。你想要的默认值只有源码能改。这一章先把三种产物的边界划清楚再带你走进源码包的目录结构最后解决一个很实际的问题版本号到底藏在哪儿。2.1 三种产物别再搞混源码包、安装包、zip 绿色版的区别我一般会直接下载源码包而不是 zip 绿色版。原因不复杂一次编译换来一劳永逸的定制权而且源码包手动编译出来的产物本身就是你私有的“绿色版”——编译、打包、独立运行不受官方更新节奏控制。先看一张对照表把三类东西的本质记住产物类型 | 里面有什么 | 能不能改默认行为 | 适合场景 安装包 | 安装程序 程序本体写入系统目录 | 不能只能改配置 | 个人装机、懒人用法 zip 绿色版 | exe、DLL、插件、主题、配置模板 | 只能改 xml 和部分菜单宏 | 临时机器、U盘随身 源码包 | 工程文件、头文件、资源文件、构建说明 | 能改完重新编译 | 定制、研究、内网分发这张表的关键结论是“改默认行为”这个需求只有源码包能接住。修改配置文件是绕过而不是解决遇到官方没有暴露的选项你连配置文件都不知道该写什么。比如把默认打开编码从 ANSI 改成 UTF-8、把多实例行为改成单实例、或者自定义标签栏中键点击的响应——这些全在源码分支里不在 xml 里。如果你是替团队做统一镜像的早点放弃绿色版直接走上源码路线后面省掉的是反复对比版本差异的麻烦。这里也顺带说一句搜 notepad zip 绿色版的人一直很多但绿色版做得再顺手也解决不了“官方行为不符合团队规范”的问题那才是你读这篇文章的真正动因。2.2 顶层目录先知道谁在管界面、谁在管编辑核心拿到源码包后第一步不是急着改代码而是认清目录分工。一个常见的源码包工程布局大致是这样的结构PowerEditor/ # 主工程目录承载 VS 工程与界面层源码 ├─ PowerEditor/ # 主工程文件所在层 │ ├─ src/ # 主程序源码窗口、命令分发、设置持久化 │ ├─ res/ # 资源文件图标、对话框、字符串、版本资源 │ └─ *.sln / *.vcxproj # 解决方案与工程文件编译入口 ├─ Scintilla/ # 编辑内核组件文本渲染、语法高亮、自动换行 ├─ Boost/ # 第三方依赖库工程构建时引用 └─ README / docs # 构建说明与历史记录这段结构是理解全文的地基界面层和编辑内核是分开管理的。菜单、对话框、设置保存、插件调度都在主程序侧具体路径大概率落在 src 里而文本编辑、光标移动、语法高亮、折叠这些底层能力全在 Scintilla 组件里。改默认编码、改标签栏行为几乎都在主程序侧完成改分词规则、改光标样式则要进 Scintilla 侧。编译时两者联动别只编一半——很多人第一次改完发现“光标行为根本没变”就开始怀疑是不是有玄学其实只是你改了 Scintilla 却用了旧的主程序或者反过来。这个双组件结构是判断“改完没生效”的第一条排查方向。注意工程文件是 .vcxproj 而不是老式的 .vcproj这说明构建系统走的是 MSBuild 路线。进入目录后先找 .sln用 VS 或命令行 msbuild 都能打开。如果你打算长期维护自己的定制分支我建议不要直接改解压出来的文件而是像第 6 章说的那样先把它变成一个 git 仓库否则改到第 10 处时你会忘掉第 1 处改了什么。2.3 版本号藏在哪改 v8.6.6 成你的版本前先找这几个位置定制版通常会顺手改版本号但版本信息不是只写在某一行里。动手前先做一次全局搜索把 8.6.6 相关的所有出现位置找全# 在源码根目录下定位版本资源和版本宏的定义文件 grep -r 8, 6, 6 --include*.rc --include*.h -n . # 按更宽的模式找版本号相关的宏定义 grep -rniE version|ver_ --include*.h -n PowerEditor/src这段命令的作用是建立“版本号分布地图”。第一个 grep 精确匹配8, 6, 6这种逗号分隔的版本写法常见于 Windows 资源文件.rc里的文件版本字段第二个 grep 用-E开启扩展正则匹配 VERSION 或 ver_ 开头的宏这类宏往往在头文件里定义编译时拼进资源。参数说明-r是递归子目录--include限定文件类型-i忽略大小写-n输出行号方便直接跳到对应行。版本信息通常不止一处资源文件里的文件版本与产品版本是一组头文件里的版本宏是另一组此外构建脚本或发布说明里可能还有一份用于升级判断的旧版本号。只改其中一个编译出的 exe 在文件属性里显示的还是旧值更麻烦的是升级逻辑会用旧值去和服务器返回的新版本比较导致你明明改成了 9.0程序仍然认为自己落后于官方。我之前吃过这个亏改了资源文件漏掉头文件结果产物的文件版本正确内部版本宏却是旧的运行时的“关于”对话框里赫然显示 v8.6.6同事直接问我是不是编错了包。这个坑会在第 5 章展开。给一个新手的操作建议把这次 grep 命中的文件路径存成一个清单批量修改时按清单逐项替换改完最后再 grep 一次确认没有遗漏。3. 把 v8.6.6 源码编译成 exe工具链取舍与最小命令源码拿到手最迫切的问题是怎么把它变成能双击运行的 notepad.exe。这一章不讲花哨的东西从环境选型到最小构建命令再到三个关键的工程开关目标只有一个——让你在本机顺利产出第一个定制版 exe。如果你以前没编译过 C 桌面程序这章值得逐行看如果你已经是熟手重点看 3.3 的三个开关这是老工程最容易翻车的配置项。3.1 环境选型为什么我建议 VS2019 而不是最新版 VS先说结论编译 v8.6.6 这类老牌 Win32 工程我优先选 VS2019 配 Windows 10 SDK而不是最新版 VS。原因是现实中的兼容性问题工程文件的工具集版本、资源编译器行为、Windows SDK 版本都存在一条“当年能编现在也能编但要多调 20 分钟配置”的隐性成本。VS2019 是照顾老工程最稳的一代基本不用改属性页就能直接开编。常见情况对比如下工具链 | 工具集 | 编译结果 | 常见麻烦 VS2019 | v142 | 一次通过率高 | 基本没有 VS2022 | v143 | 大多也能过 | 资源文件偶发报错需重设工具集 VS2017 | v141 | 可以但启动较老 | 需要额外装 v141 工具集选型不是越新越好。工程创建时是什么年代就用那个年代的周边工具链去编译这是 C 桌面项目里的通用经验。你如果因为某种原因只能用 VS2022优先检查两处一是工程属性里把“平台工具集”改成 v143 或改用“当前工具集”二是把 Windows SDK 版本改成你本机已安装的版本这两处不匹配通常会直接让加载工程失败。另外提醒一句msbuild 和 VS 的图形界面都来自同一个安装包但命令行编译需要开“开发者 PowerShell”或“VS 开发者命令提示符”否则系统 PATH 里没有 msbuild。3.2 最小构建命令从解压到第一个 exe环境准备好后构建过程其实只有几步。下面这段命令是完整的最小路径按顺序执行即可mkdir npp-build cd npp-build # 把官方源码包解压到当前目录文件名以实际下载为准 unzip ./download/notepad-8.6.6-src.zip # 进入主工程目录找到 .sln 或 .vcxproj cd PowerEditor/PowerEditor # 用 msbuild 执行 Release x64 构建/m 开启并行编译 msbuild PowerEditor.sln /t:Build /p:ConfigurationRelease /p:Platformx64 /m先解释目录跳到哪源码解压后可能出现一层套一层的目录我习惯用find . -name *.sln先定位工程文件再进入它所在的目录。命令里写的PowerEditor/PowerEditor是常见布局如果你手里的包结构不同以实际为准。/t:Build是指定编译任务/p:ConfigurationRelease和/p:Platformx64是覆盖工程的默认配置分别对应发布版和 64 位目标/m让 MSBuild 调用多核并行能明显缩短时间。首次编译因为要处理第三方依赖等上几分钟是正常的不要误以为卡死。编译完成后输出目录通常在工程目录下的Release/x64或bin/Release/x64里文件名就是 notepad.exe。验证方式很简单右键 exe 查看文件版本能显示 v8.6.6 或者你改过的版本号说明构建链路已经通了。还没开始改代码就成功编译一次这个习惯很重要——后续所有源码改动造成的“诡异问题”你都能用“原始的能不能跑”这个基准来判断不至于把环境问题误判成代码问题。3.3 工程里三个必查开关字符集、Scintilla 依赖、插件规则编译命令能过只能说明配置没崩不等于产物行为正确。我每次拿到新版本源码都会先看三个工程开关它们决定了你后续修改的生效范围开关 | 默认期待值 | 改错后果 字符集 | UnicodeUNICODE/_UNICODE | 中文路径乱码、UTF-8 文件识别错乱 Scintilla 组件 | 源码联动编译 | 改了内核代码不生效行为停留在旧内核 插件接口 | 开启插件支持 | 第三方插件全部不加载或内存崩溃第一个开关是字符集。老工程有些版本会允许你切到多字节字符集但现代文本编辑器如果不用 Unicode等于自废武功。我在模拟项目里试过一次切到 MultiByte 后编译能过但打开带中文名的文件路径直接变成问号吓得立刻切回去。第二个开关是 Scintilla 的联动编译它决定了你改的内核代码会不会被编译进主程序。如果你计划改语法高亮或光标行为务必确认工程里包含 Scintilla 项目而不是引用一个编译好的静态库。第三个开关是插件接口通常由一组宏控制关了插件系统主程序能跑但市面上大多数插件都会消失——对团队分发来说这可能是你想要的减负但对个人研究来说默认保持开启最稳妥。这三个开关的共性是它们决定了“你改的东西会不会进入最终产物”。很多人改完代码发现没变化回头一看选项压根没开。这不是逻辑问题是工程配置问题。4. 让 v8.6.6 长出你要的行为改默认编码与做内部绿色版x64 Release 版能跑起来之后真正的定制才刚开始。这一章用两个高频需求做示范一个是怎么在源码里找到主流程入口另一个是把默认打开编码从 ANSI 挪到 UTF-8。最后会讲一个内部绿色版的落地习惯哪些文件是程序本体哪些文件是用户数据两者分开之后升级和回滚都有了后悔药。4.1 从 WinMain 到消息分发改行为从哪一行开始看源码阅读最忌从头到尾一行行读。桌面程序的骨架很固定先找入口再找消息循环再找你要改的命令分支。一个典型的 Win32 程序结构示意如下方便你对着源码找对应位置// 示意结构用于理解源码分布不是原代码照抄 int APIENTRY WinMain(HINSTANCE hInst, ...) { // 注册窗口类创建主窗口随后进入消息循环 while (GetMessage(msg, nullptr, 0, 0)) { TranslateMessage(msg); DispatchMessage(msg); } return 0; } // 主窗口过程消息在这里按 WM_* 分发 LRESULT CALLBACK MainWndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) { switch (msg) { // 菜单命令、按钮点击、快捷键统一走命令消息 case WM_COMMAND: return OnCommand(hwnd, LOWORD(wp), HIWORD(wp)); // 文件拖入、窗口创建等行为各有分支 case WM_CREATE: return OnCreate(hwnd); default: break; } return DefWindowProc(hwnd, msg, wp, lp); }这段代码不是 Notepad 的原文而是 Win32 桌面程序的通用骨架作用是教你建立“主线思维”。打开源码后先搜索WinMain从入口进入跟着窗口类的注册名称找到主窗口过程再通过消息编号进入具体命令分发函数。比如你想改“打开文件时的编码检测”目标一定在“文件打开”这条命令分支里而不是在全项目搜索 encoding 然后瞎逛。我给这个习惯起了个名字先找干道再找胡同。沿着消息分发一层层走进函数看到的一定是缩进很深的调用链越靠外的越适合做策略调整越靠内的越接近底层机制改错层级就会出现“改了但被上层逻辑覆盖”的怪问题。4.2 把默认打开编码从 ANSI 改成 UTF-8一个能落地的修改思路很多团队遇到的核心痛点不是打不开 UTF-8 文件而是打开一个 UTF-8 无 BOM 文件时程序按 ANSI 猜了然后中文变成乱码。v8.6.6 的编码识别有自己的判断顺序常见的做法是找到一个负责“猜测文档编码”的函数在无法可靠识别的分支里把默认值压到 UTF-8 上。示意改动思想如下// 示意给新打开的文档设置默认代码页 // 实际工程中这行代码应放在编码识别分支里 SciMsg(hScintilla, SCI_SETCODEPAGE, SC_CP_UTF8, 0);需要说明这是示意代码不能直接粘进工程。SCI_SETCODEPAGE是 Scintilla 提供的真实消息SC_CP_UTF8是它的参数作用是告诉编辑内核把文档按 UTF-8 处理。源码里真正要做的是在“自动检测失败”以及“检测结果为 ANSI 但当前策略要求优先 UTF-8”这两个分支里把最终落点改成这行逻辑。这里有个必须提醒的副作用改完默认编码后旧的纯 ANSI 中文文档会被误识别成 UTF-8显示成乱码。所以成熟做法不是一刀切全局替换而是把“默认编码”做成一个设置项保留用户手动切换的后路。对团队分发而言建议先给一小批人试用确认你们的存量文档编码都是 UTF-8才把默认值彻底改掉。硬编码一个值是最容易的但往往不是最优解。改完之后去测试三组样本UTF-8 有 BOM、UTF-8 无 BOM、ANSI 中文分别确认打开表现符合预期这一步能帮你筛掉一半的“改完更糟”情况。4.3 编译产物落地方案把自制版整理成内部 zip 绿色版编译完成、行为也验证过之后下一步是分发。很多人以为把 exe 拷走就行结果同事打开后插件没了、主题变了、配置乱套。一个自制的绿色版需要分清程序本体和用户数据。常规文件清单如下文件或目录 | 性质 | 说明 notepad.exe | 程序本体 | 每次升级替换的对象 SciLexer.dll如有 | 程序本体 | 部分构建方式下是静态嵌入无此文件 themes/ | 程序本体 | 主题外观不改可不带 plugins/ | 程序本体 | 插件及插件配置 config.xml | 用户数据 | 记录了界面布局、快捷键、最近文件 session.xml | 临时数据 | 崩溃恢复和会话记录可删我一般的打包习惯程序本体做成一个压缩包配置单独存放。首次分发给同事时压缩包里放一份干净的 config.xml后续升级只替换 notepad.exe 和依赖的 DLLconfig.xml 保留不动这样同事的自定义快捷键和布局不会被覆盖。反过来如果某个版本把配置改坏了让同事删掉 config.xml 重启程序会自动生成一份默认配置——这就是自制绿色版的后悔药。所谓绿色版不是解压就能用而是你永远知道哪份文件是用户数据、哪份文件是程序本体这份“知道”才是它可维护的前提。5. v8.6.6 源码编译避坑实录五条每次都有人踩的坑源码编译这件事情最大的特点就是“错误信息不说人话”。下面这五条坑每一条都是我从实际编译和分发过程中反复遇到、并且和同行确认过真实存在的典型问题。每条按现象、原因、解决三段式写你可以当排查手册用遇到类似报错直接对号入座。5.1 现象打开 .rc 资源文件就报错报错行号指向一片空白这是用新版 VS 打开老工程时的经典问题。现象是资源编译器报错但跳转过去报错行看起来干干净净根本没有任何可疑字符。原因是资源文件的编码或 BOM 格式与当前资源编译器的预期不一致编译器读到了它不认识的字节序标记于是把错误记在了一行的开头。解决办法是用 VS 或任意编辑器打开 .rc 文件把文件另存为 UTF-8 with BOM再重新编译。注意存完之后不要大改内容只做编码转换。处理完一个如果还有报错继续看下一个 .rc 文件因为资源文件是逐个编译的。5.2 现象x64 编译成功了但第三方插件一个都不加载排除了插件开关问题之后最常见的元凶是位数不匹配。第三方插件分为 32 位和 64 位两个阵营你的主程序编译成 x64就需要 x64 版本插件。如果 plugins 目录里放的是 32 位 DLL程序会直接忽略甚至在插件管理器里看不到它们。解决方法是先确认你编译的主程序是 Win32 还是 x64然后去插件发布页下载对应的位数版本。这个坑之所以隐蔽是因为 exe 能正常启动插件目录也存在你甚至会怀疑是插件接口被注释了。判断技巧很简单看任务管理器里进程是否带 x64 标志或者直接检查 DLL 的位数信息。5.3 现象本机跑得好好的换一台机器就报缺少 DLL这不是源码问题是运行库依赖问题。Release 默认使用动态链接的 C 运行库目标机器如果没有安装对应的 VC 运行库就会在启动时弹窗报错。解决路径有两条一是打包时带上运行库安装包二是修改工程属性把代码生成方式从 /MD 改成 /MT 静态链接。改 /MT 之后exe 体积会明显变大但换来的是目标机器不用预装运行库。对内部小范围分发我建议直接改 /MT对要长期跟进上游更新的团队则更推荐保留默认并写清部署文档因为静态链接会让你每次升级都多检查一遍这个属性。5.4 现象版本号明明改成 9.0系统里却仍然显示 v8.6.6这就是第 2.3 节埋的雷。版本号在源码里分布不均改一处只影响文件属性里的显示改另一处才影响软件内部的关于页和升级判断。现象是你改了资源文件但头文件里的版本宏没动编译出来的一部分代码拿旧值去比较。解决方法是回到 2.3 的 grep 命令把命中版本号的所有文件全部列出来逐处修改并记录最后用同样命令再跑一次做确认。我再补充一个技巧批量替换时注意区分“逗号分隔”和“点分隔”有的地方写8,6,6有的写8.6.6两套格式都搜一遍。5.5 现象同时装了两份自制版配置互相覆盖乱套自己编译的版本和官方版本共存时会出现“我改的配置跑到官方版上去了”的乱象。原因是程序默认使用系统级的配置目录或注册表位置两份不同 exe 共用同一套用户配置。解决方法是做隔离把自制版放到独立目录并为其指定独立的配置文件路径让两份程序各用各的配置。具体参数因版本而异但思路是一致的——不要依赖默认配置位置强制把配置目录拉到 exe 所在目录或自定义目录。这个坑对团队分发影响最大因为一旦同事同时装着官方版和你的自制版两个版本会互相干扰出现的现象极其诡异排查时优先怀疑配置串台而不是源码问题。6. 让改动可追溯用补丁管理你的 v8.6.6 源码定制做到第十次改动时你会发现自己记不住都改过什么。我过去的做法很原始直接在解压目录里改改到第三周想回退一处修改已经忘了原始代码长什么样。后来我养成了一个习惯解压源码后的第一时间就把它交给源代码管理工具。这不只是“记录改动”更是给你自己的排查留后路。# 解压完成后立即初始化仓库 cd PowerEditor git init git add . git commit -m vendor: import Notepad v8.6.6 官方源码基线这个初始提交起的名字很有讲究它标记的是“未修改的原始基线”。之后每完成一个功能改动就单独提交一次提交信息写清楚改了什么、为什么改。这样做的直接收益是任何一次修改出问题你都能git diff查看与基线的差异也能回退到任意一个历史状态。对源码定制来说git 仓库就是你的时光机。另一个配套习惯是验证。每次改动后除了运行程序手动点一遍我还会用一条命令确认产物版本正确# 验证编译产物的文件版本与产品版本 (Get-Item .\x64\Release\notepad.exe).VersionInfo | Select-Object FileVersion, ProductVersion这条命令读的是 Windows 文件属性里的版本信息能直接确认资源文件版本是否已经更新。再配合运行期打开“关于”对话框做一次产品版本确认两处一致说明第 2.3 节埋下的版本宏坑没有踩中。我个人的警觉点是每次提交都带着这两个验证结果一起记录三个月后回看提交历史能立刻看出哪次改动改了版本、哪次改动改了编码逻辑、哪次改动引入了问题。这套把“改代码”和“记变更”绑在一起的习惯帮我避免过至少两次从头排查的灾难。希望你从第一次定制就开始用别走我当年直接改压缩包的老路。希望帮到你。本文还有配套的精品资源点击获取