
简介这份压缩包是 Notepad 8.4.1 的完整源码面向想要深入学习C编程、研究编辑器底层实现或计划二次开发的开发者。包内汇集1799个文件以C/C头文件与源文件h、cxx、cpp、hpp为主体同时包含界面资源ico、bmp、rc、XML配置、Python辅助脚本、构建工程文件和说明文档既能用于完整编译也便于按模块阅读核心代码。整个包仅10.19MB下载与解压都很轻量。目前已有402人学习。源码覆盖多语言语法高亮、宏录制、正则替换、插件系统等关键模块通过研读这些代码可以直观理解一个成熟开源编辑器的架构设计也可在此基础上定制功能、编写新插件或向社区提交补丁适合有一定C基础、希望从源码层面提升工程能力的中高级开发者。1. Notepad 8.4.1 源码包不是安装包而是能自己编译的完整工程notepad-plus-plus-8.4.1.zip 解压之后里面没有常见的 setup.exe而是一批 .bat 脚本和一个 .asc 公钥文件——这是源码包不是绿色版安装包。它的价值在于你能亲手编译出属于自己的 Notepad改源码、加插件、去掉不想要的功能而不是只当一个用户。这份资源适合两类人一是想通过成熟开源项目学 C GUI 与多线程编程的开发者二是有定制需求、想把编辑器行为改成自己习惯的 IT 从业者。它不解决“装个编辑器”的问题解决的是“看懂并改造这个编辑器”的问题。2. 先摸清这个 zip 装了什么构建脚本、签名公钥与测试入口2.1 六类文件各自承担什么角色解压后看到的文件虽少但每样都有明确用途。文件名类型作用AllStyles.adocAsciiDoc 文档列出所有语法高亮 style 样式是研究词法高亮的第一手文档nppGpgPub.ascGPG 公钥验证官方发布包的签名用来确认源码未被篡改x.aspASP 样例用于验证 ASP 语法高亮渲染的测试文件packageAll.bat构建脚本一键编译主程序、收集产物、打包发布zipsrc.bat构建脚本把当前源码树打包成 zip用于分发源码delbin.bat清理脚本删除 bin 目录的编译产物与中间文件RunTest.bat测试脚本运行自动化冒烟测试检查核心功能是否正常这些文件组合在一起构成一条完整的“清理 → 构建 → 测试 → 打包”流水线。真正的 C 源码不会平铺在 zip 根目录而是在解压后的 PowerEditor、Scintilla、Lexilla 等子目录里。根目录放脚本是开源项目常见的组织方式脚本负责流程代码库负责功能。2.2 packageAll.bat 的构建指挥逻辑用文本编辑器打开 packageAll.bat能看到它做的事情和手工构建完全一致只是顺序被固定成了脚本。核心步骤可以概括为先调用 Visual Studio 的工具链环境再用 devenv 或 msbuild 编译 Npp.sln 解决方案最后把产物复制到 bin 目录。echo off rem 第一段加载 Visual Studio 环境变量找到 cl.exe、devenv.exe if not defined VSINSTALLDIR ( call %ProgramFiles%\Microsoft Visual Studio\2022\Community\Common7\Tools\VsDevCmd.bat -archx64 ) rem 第二段编译主程序输出 Release 配置的 notepad.exe msbuild PowerEditor\visualc\Win32\Npp.sln /m /p:ConfigurationRelease /p:PlatformWin32 /v:m rem 第三段把 dll、语言包、插件目录拷到 bin 下 xcopy /E /I /Y PowerEditor\bin\*.* rem 第四段按版本号打 zip生成可分发安装包 powershell -Command Compress-Archive -Path PowerEditor\bin\* -DestinationPath release\npp.8.4.1.zip第一段的作用是导入编译器环境不执行的话 msbuild 找不到工具链会直接在命令行报 build failed第二段是构建主体/m开启多核并行编译、/p:ConfigurationRelease指定发布配置、/v:m把日志级别设为中等方便观察错误第三段负责把语言翻译文件如 ChineseSimplified.xml、SciLexer.dll、插件目录一起复制到 bin第四段用 PowerShell 压缩产物最终生成可直接分发的 zip。注意 /m 参数在多核机器上能显著缩短编译时间但如果是老机器建议去掉避免内存不足导致编译进程被杀。2.3 zipsrc.bat 与 RunTest.bat反向流程的两块拼图zipsrc.bat 是 packageAll.bat 的逆向操作它把当前源码树重新打包成 zip。常见做法是先排除 build 产物和 .git 目录再调用 PowerShell 的 Compress-Archive 或第三方工具压缩。echo off rem 删除 bin 等构建产物避免把中间文件打进源码包 call delbin.bat rem 打包源码目录 cd /d %~dp0 powershell -Command Get-ChildItem -Exclude bin,obj,.git | Compress-Archive -DestinationPath notepad-plus-plus-8.4.1-src.zip参数说明-Exclude用于排除编译产生的中间目录否则包体积会膨胀好几倍-DestinationPath指定输出文件cd /d %~dp0把工作目录切到脚本所在路径避免在绝对路径含空格时出错。RunTest.bat 通常调用测试项目生成的 NppUnitTests.exe跑完会输出通过率。判断测试是否通过的通用做法是看有没有出现 0 failed 之类的关键字即使不写自动化断言至少能确认构建后程序能启动、核心菜单能弹出。提示如果 RunTest.bat 报找不到测试程序多半是测试工程没编出来回到 Visual Studio 里单独编译 NppUnitTests 项目再跑。3. 从源码到可执行程序一次完整的构建实验3.1 构建环境清单Visual Studio 版本与依赖项Notepad 8.4.1 是基于 C 的 Windows 桌面程序构建环境基本被 Visual Studio 生态锁死。这里是常见的完整环境清单依赖项说明获取方式Visual Studio 2019/2022需要「使用 C 的桌面开发」工作负载官方安装器勾选Windows SDK 10.xVS 安装时默认附带提供 API 头文件与库VS 组件Scintilla编辑控件源码提供代码着色与编辑能力源码目录或 Git 子模块Lexilla词法分析库负责语法高亮的 lexer 实现同源码目录Boost可选仅在使用带正则增强特性时需要vcpkg 或官方包GDI系统自带旧版本需手动链接 Gdiplus.lib系统组件Scintilla 和 Lexilla 是决定 Notepad 能不能跑起来的关键依赖两者通常以 Git 子模块存在于源码树的根目录。如果你下载的是非完整版 zip 包这两个目录可能缺失后面避坑章节专门讲。3.2 用 packageAll.bat 走一遍完整构建拿到源码后别急着打开 sln先尝试脚本路径因为脚本路径能暴露环境变量是否配好。cd /d notepad-plus-plus-8.4.1 packageAll.bat build_log.txt 21 type build_log.txt | find Build succeeded第一次跑通常会看到两种情况要么直接输出 Build succeeded 后进入打包阶段要么在中途因缺少依赖报致命错误。日志输出重定向到 build_log.txt 是最重要的习惯——脚本一闪而过时日志能告诉你到底死在哪一行。21把标准错误也并入文件否则编译器的 fatal error 不会进 build_log.txt只会在屏幕上闪一下。如果构建成功bin 目录下应出现 notepad.exe。双击运行系统托盘出现图标、主窗口出现文本编辑区就说明基础构建通过。3.3 手工构建切换 Debug/Release 与 x86/x64脚本默认用 Release Win32 配置。想调试源码则必须切到 Debug——否则断点命不中、变量看不全。# 在 PowerShell 里手动执行 MSBuild覆盖脚本默认配置 msbuild PowerEditor\visualc\Win32\Npp.sln /p:ConfigurationDebug /p:PlatformWin32 /v:m参数说明/p:PlatformWin32指定 32 位目标Notepad 官方默认就是 x86兼容性最好/p:ConfigurationDebug生成带调试符号的版本适合在 Visual Studio 里直接打断点跟踪。如果切到 x64需要先去 Scintilla 目录单独编一版 64 位的 SciLexer.lib再回来编译主工程否则链接阶段会报 unresolved external symbol 错误。3.4 验证构建产物的完整性构建完成后不要只看 exe 存在就收工一套能用的 NPP 还包括动态库、插件接口和语言包。检查重点是以下文件文件缺失后果notepad.exe主程序不存在等于没编译SciLexer.dll编辑器控件缺位程序无法启动或直接崩溃plugins\ 目录所有第三方插件失效localization*.xml界面语言全部变英文nativeLang.xml语言选择器异常我一般会右键 notepad.exe 查看版本号确认是 8.4.1.0 而不是编译出来的旧版本再打开插件管理对话框能正常列出插件才说明插件体系完整。4. 读源码的三条主线入口函数、编辑控件与词法高亮4.1 从 WinMain 到消息循环程序入口在哪Notepad 的主体代码在 PowerEditor/src 下入口是标准的 Windows 应用程序入口 WinMain。初次读源码的人先找到 WinMain 和它调用的 NppMain从这里出发能最快理解程序的主线流程。// 入口初始化应用实例、加载命令行参数、启动主窗口 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow) { // 1. 创建唯一实例控制防止重复打开多个编辑器实例 if (!checkAlreadyRunning(hInstance)) return 0; // 2. 初始化全局参数路径、配置目录、命令行开关 NppParameters params NppParameters::getInstance(); params.init(hInstance); // 3. 进入主窗口消息循环所有命令菜单事件在此分发 NppMain(hInstance, hWndParent, nCmdShow); return 0; }三段式结构解释了 Notepad 的运行逻辑先阻止多实例导致配置互踩再初始化配置参数最后进入主循环。读这个入口时不要纠结每个基类细节先记住“配置参数先行、消息循环在后”的原则整个 UI 框架都围绕这个原则展开。4.2 Scintilla 与 Lexilla编辑器底座怎么分工Scintilla 是一个开源编辑控件提供文本编辑、滚动、快捷键、选择、撤销重做这些最基础的能力Lexilla 是它配套的词法分析器集合负责在输入文本时按语言规则标出关键字、字符串、注释等 token。Notepad 的角色更像一个壳把 Scintilla 控件嵌入主窗口再通过 Lexilla 的 lexer 驱动语法着色。// 初始化编辑器的核心调用把 Scintilla 窗口挂到 NPP 的容器上 void EditorView::init(HINSTANCE hInst, HWND hParent) { // 1. 创建 Scintilla 编辑窗口指定 Unicode 编码模式 hScintilla CreateWindowExA(0, Scintilla, , WS_CHILD | WS_VSCROLL, 0, 0, 0, 0, hParent, nullptr, hInst, nullptr); // 2. 启用 Lexilla 词法分析支持给编辑控件绑定 lexer 工厂 SendMessage(hScintilla, SCI_SETILEXER, 0, (LPARAM)CreateLexerFactory()); // 3. 设置默认字体与样式对应 AllStyles.adoc 里 Style 1..n 的定义 SendMessage(hScintilla, SCI_STYLESETFONT, STYLE_DEFAULT, (LPARAM)Consolas); }理解这一层对做插件非常重要你调用的大部分编辑能力最终都通过 SciTE 消息SCI_XXX 系列发给 Scintilla 控件而不是直接操作 Windows 原生控件。只要拿到编辑器的 HWND就可以用 SendMessage 跨进程或跨线程控制文本区域很多自动化脚本就是这么做的。4.3 从 AllStyles.adoc 读懂 50 多种语法高亮的组织方式AllStyles.adoc 是这份 zip 里被很多人忽略的文档但它是研究语法高亮的第一入口。它把每种语言对应的 style id、前景色、背景色、粗斜体属性全部列出来了。语言默认 style高亮要素C/CSCE_C_DEFAULT 等 20 个关键字、字符串、预处理指令PythonSCE_P_DEFAULT 等 10 个def/class 关键字、三引号字符串ASPSCE_ASP_DEFAULT 等服务端脚本与 HTML 混排规则这份文档的作用是当“风格字典”查你改一个语言的高亮颜色只要找到该语言的 style id然后在代码里对应位置修改 SCI_STYLESETFORE 即可。x.asp 文件则是拿来验证 ASP 高亮效果的样例编辑源码时把它拖进去切换语言模式能看到即时渲染结果。5. 避坑指南源码编译与二次开发最常见的坑5.1 现象packageAll.bat 一闪而过不知道发生了什么双击运行脚本窗口一闪就关闭没有留下任何输出。原因脚本内部某个命令失败后不会暂停常见于 VSINSTALLDIR 未定义时 msbuild 直接找不到工具链加上日志输出没重定向错误信息全丢了。解决用命令行方式执行并重定向输出cmd /c packageAll.bat log.txt 21再去 log.txt 里找第一个 error。90% 的情况是 Visual Studio 环境变量没加载先手动call VsDevCmd.bat就好。5.2 现象编译报错找不到 Scintilla.h / Lexilla.hMSBuild 进行到 Scintilla 相关源文件时报 fatal error C1083: Cannot open include file: Scintilla.h。原因源码 zip 里没有包含 Git 子模块的内容Scintilla 和 Lexilla 是独立仓库不随主源码包一起分发。解决确认源码树根目录下有没有 Scintilla 目录没有的话进入对应位置手动补齐依赖。官方仓库的标准做法是git submodule update --init --recursive对这份 zip 包常见做法是从 Scintilla 官方发布包单独下载把 include 目录放到源码树对应的 include 路径下再重新执行构建。5.3 现象Release 构建成功但双击图标立刻崩溃构建日志干净产物也齐全但运行不到一秒就弹错误或闪退。原因最常见的是旧配置残留。%APPDATA%\Notepad 下有以前版本留下的 config.xml 或 plugins 文件夹8.4.1 的主程序读到了不兼容的配置。解决用干净配置模式启动验证notepad.exe -lNotepad或直接临时改名 %APPDATA%\Notepad 为别的名字再启动。能正常起来就把插件逐个搬回来定位是谁不兼容。5.4 现象切到 x64 配置后链接报 unresolved external symbol配置管理器里把平台切到 x64链接时报一堆 SciLexer.lib 的符号找不到。原因SciLexer.lib 在构建主程序前就被编译成了 Win32 版本x64 链接器找不到对应符号。Notepad 主程序默认只编 Win32x64 需要先把 Scintilla 自己编成 64 位。解决先到 Scintilla/win32 目录单独执行 x64 配置的构建生成 64 位 SciLexer.lib再把该库路径加入主工程的链接目录最后编译主程序。顺序颠倒必然失败。5.5 现象插件能加载但菜单命令点了没反应插件已出现在插件菜单里但点击自定义命令NPP 无响应或弹空提示。原因插件接口的 message 处理函数没有正确实现最常见的是没有调用 NPPMSG 相关的消息分发或者函数签名返回类型不对。解决在插件的PluginMessage回调里打印日志或用 OutputDebugString 输出调用链对照官方插件示例逐行检查。单步调试时把插件项目和 NPP 主工程放在同一个解决方案里断点才能命中插件代码。6. 进阶验证手写一个最小插件挂进 8.4.1最后做一个最小插件来验证整个体系是否真的打通。这里做一个最简单的插件注册一个菜单项点了之后在文档开头插入一行时间戳。#include windows.h #include plugins/PluginInterface.h // NPP 提供的插件接口头文件 const TCHAR PLUGIN_NAME[] TEXT(TimeStampDemo); NppData g_nppData; // 插件入口注册菜单与命令 extern C __declspec(dllexport) void setInfo(NppData nppd) { g_nppData nppd; } // 菜单命令回调 extern C __declspec(dllexport) void command(int id) { if (id 0) { // 我们的第一个菜单项 HWND hEdit g_nppData._scintillaMainHandle; // 在当前位置插入系统时间字符串 SYSTEMTIME st; GetLocalTime(st); wchar_t buf[64]; swprintf(buf, 64, L[%04d-%02d-%02d %02d:%02d:%02d]\r\n, st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond); SendMessage(hEdit, SCI_INSERTTEXT, 0, (LPARAM)buf); // 通过 Scintilla 消息插入文本 } }把该文件编译成 TimeStampDemo.dll放到 NPP 的 plugins 目录下重启编辑器。插件菜单里出现 TimeStampDemo点击后光标处多出一行时间戳说明插件接口、Scintilla 消息通道和 dll 导出三个环节全部打通。这一步跑通后续做更复杂的格式化、补全、批处理插件就只是工作量问题不再是未知技术。从那以后我每次拿到新的 npp 源码包都强制自己先跑一遍这个最小插件验证流程先确认构建再确认 Scintilla 消息可用最后才动业务代码。这套流程帮我避开了不少“代码看着对但系统不认”的玄学问题。希望帮到你。本文还有配套的精品资源点击获取