欢迎加入开源鸿蒙 PC 社区:https://harmonypc.csdn.net/

欢迎在 PC 社区平台申请新建项目:https://atomgit.com/OpenHarmonyPCDeveloper

适配开源地址:https://atomgit.com/OpenHarmonyPCDeveloper/ohos_notepad-plus-plus

环境搭建文章:https://blog.csdn.net/weixin_52908342/article/details/161343743

一、为什么要适配 Notepad++

Notepad++ 是 Windows 平台上最具代表性的轻量级代码编辑器之一。它启动快、资源占用低,同时提供多标签编辑、语法高亮、查找替换、编码转换、代码折叠、书签等高频能力。对于开发者和需要处理日志、配置文件的普通用户来说,这类“随开随用”的本地编辑器仍然有不可替代的价值。

HarmonyOS PC 的应用生态正在逐步完善,但成熟的桌面文本编辑工具仍然偏少。我们希望验证一条更具普适性的迁移路线:面对一个长期依赖 Win32 的大型 C++ 桌面应用,能否不把它改造成网页编辑器,而是保留经过多年验证的原生编辑内核,并在鸿蒙 PC 上重新建立稳定的窗口、文件和交互体系。

上游 Notepad++ 版本为 8.9.6,编辑内核为 Scintilla 5.6.3,词法分析组件为 Lexilla 5.5.0。鸿蒙版本延续 GPL-3.0 许可证。

二、先做判断:这不是一次普通的跨平台编译

Notepad++ 的原始工程是纯 Win32 C++ 应用。菜单、工具栏、标签页、对话框、消息循环、绘图以及大量系统集成功能都直接依赖 Windows API。在 PowerEditor 的 285 个源文件中,有 160 个文件引用了 HWND、GDI 或 Windows 消息相关接口。若从界面层逐项替换这些调用,不但工作量大,也很难保证后续维护质量。

不过,Notepad++ 的代码并不是一个无法拆分的整体。它的核心大致可以分为三层:

层次原项目实现鸿蒙适配策略
编辑内核Scintilla保留平台无关核心,并采用官方 Qt 移植层
词法高亮Lexilla全量参与鸿蒙侧 C++ 编译
桌面外壳PowerEditor / Win32使用 Qt Widgets 重建高频编辑工作流

Scintilla 的文档模型、文本存储、撤销栈、搜索、选区和渲染模型基本都是平台无关的标准 C++;Lexilla 的绝大部分词法器同样可以直接复用。真正无法直接迁移的是 Win32 外壳。因此,本次适配最终采用“真引擎、新外壳”的方案,而不是从零重写一个外观相似的编辑器。

这里没有选择 Electron。原因很直接:Notepad++ 本身不存在可复用的 Web 前端。如果改走 Electron,就需要用 Monaco 或 CodeMirror 重做编辑器,同时还要把原有 C++ 能力拆成鸿蒙 arm64 可用的原生扩展,迁移成本和运行时体积都会明显增加。Qt for OpenHarmony 已经提供 Qt Widgets、鸿蒙 QPA 平台插件和 Scintilla 官方 Qt 适配层,更适合这类 C++ 原生项目。

三、整体架构

鸿蒙工程位于仓库根目录的 harmony_pc/。ArkTS 负责 Ability 生命周期、文件 URI 接收和 XComponent 宿主,Qt 负责桌面窗口与交互,Scintilla 和 Lexilla 继续承担编辑器核心能力。

EntryAbility
    └── Index.ets / XComponent
          └── Qt for OpenHarmony QPA 插件
                └── libentry.so
                      ├── Qt Widgets 桌面外壳
                      ├── Scintilla 5.6.3 编辑内核
                      ├── Lexilla 5.5.0 词法器
                      └── Boost PCRE 正则搜索

工程中的主要目录如下:

ohos_notepad-plus-plus/
├── PowerEditor/                         # 上游 Win32 外壳,原样保留
├── scintilla/                           # Scintilla 核心与官方 Qt 移植层
├── lexilla/                             # 词法器源码
├── boostregex/                          # Boost PCRE 搜索实现
└── harmony_pc/
    ├── AppScope/app.json5               # 应用级配置
    ├── build-profile.json5              # SDK、产品与签名配置
    ├── qtforharmony_sdk/                # Qt 5.15.12 for OpenHarmony SDK
    └── entry/
        ├── libs/arm64-v8a/              # QPA 平台插件
        └── src/main/
            ├── ets/                     # Ability、XComponent 与 URI 处理
            ├── module.json5             # 2in1/tablet 及文件关联声明
            └── cpp/
                ├── CMakeLists.txt       # C++ 整体构建入口
                └── npp/                 # 新实现的 Qt Widgets 外壳

应用启动时,EntryAbility 加载 Index.ets,页面创建 NODE 类型的 XComponent;QPA 插件随后加载 libentry.so 并调用导出的 main()。当用户从文件管理器再次打开文本文件时,应用不会新建一套编辑器进程,而是把路径转交给已有窗口,复用当前会话。

四、核心适配过程

1. 让 Scintilla 和 Lexilla 进入 HAP

harmony_pc/entry/src/main/cpp/CMakeLists.txt 是原生构建的中心。Scintilla 平台无关源码、官方 ScintillaEditBase Qt 移植层、Lexilla 全量词法器、Boost 正则实现以及新的 Qt 外壳最终共同生成 libentry.so

Scintilla 5.x 要求 C++17,并依赖 C++ 异常机制;鸿蒙 Native 工具链的默认参数并不完全覆盖这些要求,因此工程中显式设置了:

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
target_compile_options(entry PRIVATE -fexceptions -frtti)

Lexilla 中唯一明显的 Windows 依赖位于 LexUser.cxx:该文件包含 windows.h,但实际只使用 _itoa。适配时没有粗暴移除用户自定义语言词法器,而是对 Windows 头文件增加平台守卫,并在非 Windows 平台使用 snprintf 提供等价实现。这样既保留了 Lexilla 的完整注册表,也不影响原 Windows 工程的构建行为。

2. 重建桌面外壳,而不是照搬 Win32 窗口

新的 Qt Widgets 外壳保留了 Notepad++ 最常用的操作路径:

  • 多标签新建、打开、保存、另存为和关闭确认;
  • 撤销、重做、剪切、复制、粘贴与行操作;
  • 行号、当前行高亮、括号匹配、书签和代码折叠;
  • 工具栏、菜单栏、状态栏以及可停靠的功能面板;
  • 浅色和深色主题、简体中文界面以及首选项持久化。

界面并未机械复刻 Windows 版的每一个像素。鸿蒙 PC 存在不同的窗口缩放和输入设备组合,因此工具栏按钮、菜单点击区域、滚动条宽度、标签页高度和状态栏信息密度都重新做了适配。目标是在保留 Notepad++ 使用习惯的同时,满足 PC 大屏和 HiDPI 环境下的可读性与可点击性。

以下运行画面均采集自 HarmonyOS PC 2in1 真机。测试设备分辨率为 3120×2080,安装包为本项目生成的 arm64-v8a 签名 HAP。

在这里插入图片描述

3. 恢复代码编辑器的“手感”

仅能输入文字还不足以称为代码编辑器。鸿蒙版本接入了 Lexilla 全量词法器,在外壳中为 40 种常用语言配置了扩展名识别、关键字和默认配色;用户也可以通过语言菜单手动切换。代码折叠、智能高亮、自动缩进和基于当前文档的单词补全直接建立在 Scintilla 的消息接口上,因此编辑行为与原版保持了较高的一致性。

多标签并不是多个普通文本框的拼接。每个标签都维护文件路径、编码、换行符类型、语言模式、修改状态和光标位置。分屏模式则让两个视图共享同一份 Scintilla document,两侧编辑能够实时同步。

在这里插入图片描述

4. 查找替换不能只做一个输入框

Notepad++ 的高频价值很大一部分来自搜索能力。鸿蒙版本实现了当前文档查找与替换,支持大小写匹配、全词匹配、循环查找、全部替换、跳转到行和正则表达式。正则搜索接入项目原有的 Boost PCRE 实现,而不是改用行为存在差异的临时方案。

“在当前文档中全部查找”的命中项会进入搜索结果面板,点击结果可回到对应行。这个闭环对查看日志、修改配置和批量处理源码非常实用。

在这里插入图片描述

项目还实现了目录级“在文件中查找”和批量替换。搜索面板支持目录递归、文件过滤器、大小写、正则表达式、子目录开关与取消操作;结果以树形结构呈现,点击后可直接定位文件和行号。批量替换前会要求确认,并统计成功替换与跳过的文件数量,避免目录操作悄无声息地修改数据。

在这里插入图片描述

5. 处理鸿蒙文件 URI 与沙箱边界

桌面编辑器必须能从文件管理器打开文件,但 HarmonyOS 应用接收到的往往不是普通 POSIX 路径,而是 file://content:// URI。Qt 编辑内核无法假设这些 URI 都能直接用 QFile 读取。

适配中在 ArkTS 层先接收 Want URI,再使用系统文件接口把外部文件复制到应用缓存目录,最后将可访问的本地路径传给 Qt。module.json5 同时声明了纯文本、Markdown、XML、HTML、JSON 及常见源码类型的文件关联。二次唤起时,Qt 侧会复用已有主窗口并打开新文件,避免产生多个相互独立的会话。

这条链路解决了“能从应用内打开文件”与“能从系统文件管理器唤起编辑器”之间的差别,也是本次适配中最容易在桌面调试环境里被忽略的一环。

6. 编码与换行符必须可控

代码编辑器面对的并不总是 UTF-8 文件。鸿蒙版本支持 UTF-8、UTF-8 BOM、UTF-16 LE/BE、GB18030、Big5、Shift-JIS、EUC-KR 和 Windows-1252 等常见编码,并可按指定编码重新加载或保存。换行符会在打开时自动检测,也可以在 CRLF、LF 和 CR 之间转换。

这里遇到过一个 Qt 5 兼容细节:QByteArray::operator[] 返回 QByteRef,无法直接参与 std::swap。UTF-16 字节序交换最终改为通过 data() 取得裸指针后处理。问题不大,但如果只在 UTF-8 样本上测试,很容易把它留到真机处理实际文件时才暴露。

在这里插入图片描述

五、适配中遇到的几个难点

难点一:平台边界比编译错误更重要

最初容易把注意力集中在头文件和编译参数上,但真正决定迁移质量的是边界划分。如果执着于让 PowerEditor 在鸿蒙上逐文件通过编译,就会长期陷在 HWND、GDI 和消息循环的替换中。先把 Scintilla、Lexilla 与 Win32 外壳分开,才让工程从“移植整个 Windows 应用”变成了“保留编辑引擎、重做宿主”。

难点二:Qt 工具链不只有目标端动态库

Qt 的 AUTOMOC 需要在构建机上执行 moc。随项目使用的 Qt SDK 不仅包含鸿蒙 arm64 库,也包含构建机侧工具;如果为了减小仓库体积只保留目标端 .so,CMake 配置可能通过,但真正编译时会在元对象生成阶段失败。因此 Qt SDK 的工具、头文件、CMake 配置和目标库必须保持同一版本。

难点三:Ability、XComponent 与 Qt 生命周期需要对齐

Qt 主窗口并不是由 ArkTS 页面直接绘制,而是通过 XComponent 和 QPA 插件启动。首屏 loadContent 与 Qt 应用启动存在时序交错;文件关联又会触发 onNewWant 和二次启动分支。模板中曾调用一个类型声明存在、但当前 QPA 插件并未导出的实例查询函数,首次启动没有暴露问题,文件关联二次唤起时却会直接触发运行时异常。适配时增加了运行时能力判断,并以固定实例标识兜底,使其符合单实例编辑器的语义。

难点四:签名与包名、真机强绑定

调试签名的 Profile 与 bundleName、设备信息和有效期绑定,不能把其他项目的签名材料直接复制过来。当前应用包名为 org.notepadplusplus.editor,更换包名或测试设备后都应在 DevEco Studio 中重新生成匹配的调试签名。只有签名、安装、系统文件关联和二次唤起全部在真机上跑通,才算完成桌面编辑器的基本交付闭环。

六、编译、安装与启动

使用 DevEco Studio 时,应打开仓库下的 harmony_pc/,等待工程同步完成。首次运行前,在 File > Project Structure > Signing Configs 中为当前包名配置调试签名,然后选择 entry 模块运行,或执行 Build > Build Hap(s)

命令行构建可使用:

cd harmony_pc
hvigorw clean --no-daemon
hvigorw assembleHap --no-daemon

产物位于:

harmony_pc/entry/build/default/outputs/default/
├── entry-default-unsigned.hap
└── entry-default-signed.hap

安装与启动命令如下:

hdc install harmony_pc/entry/build/default/outputs/default/entry-default-signed.hap
hdc shell aa start -a EntryAbility -b org.notepadplusplus.editor -m entry

当前工程已能生成 arm64-v8a 的 libentry.so 及签名 HAP。真机验收时建议依次检查:冷启动、中文输入、新建和保存、多标签、语法高亮、查找替换、目录搜索、编码转换、文件管理器关联打开、二次唤起和会话恢复。截图应取自真机实际运行界面,并使用真实文件完成操作,避免只证明静态首页能够显示。

七、当前功能边界

目前已经覆盖日常代码与文本编辑的主线能力:

  • 新建、打开、保存、另存为、关闭确认和最近文件;
  • 多标签、分屏、会话恢复、光标位置记忆和外部文件变更监测;
  • 语法高亮、代码折叠、自动缩进、自动补全、书签和智能高亮;
  • 当前文档查找替换、目录搜索、目录批量替换和增量搜索;
  • 常见文本编码读写、编码重载和 CRLF/LF/CR 转换;
  • Document Map、Function List、宏录制与回放;
  • 浅色/深色模式、简体中文界面和鸿蒙文件关联。

没有纳入当前版本的主要是与 Windows 桌面生态深度绑定的部分,包括 Win32 DLL 插件系统、完整 UDL 图形配置、打印、Shortcut Mapper、Style Configurator、完整多语言包以及宏的持久化管理。这些能力并非简单链接一个库就能恢复,需要结合 HarmonyOS 的插件安全模型、打印服务和系统集成方式重新设计。

因此,鸿蒙版本的定位不是 Windows 版 Notepad++ 的逐项克隆,而是一款保留 Scintilla/Lexilla 核心、具备 Notepad++ 高频工作流的鸿蒙 PC 原生代码编辑器。对迁移项目而言,这种边界明确、核心真实可用的实现,比“界面看起来一样但编辑能力另起炉灶”更有长期维护价值。

八、总结

Notepad++ 的适配说明了一件事:传统 Win32 C++ 应用并不一定只能整体重写。只要先识别出平台无关内核与系统专属外壳,就可以把迁移工作收敛到可维护的范围内。

本项目保留了 Scintilla 的文档和编辑能力、Lexilla 的词法分析能力以及 Boost PCRE 搜索行为,用 Qt Widgets 重建鸿蒙 PC 桌面外壳,再通过 ArkTS、XComponent 和 QPA 插件接入 HarmonyOS 应用生命周期。最终形成的不是一个 Web 包装页,而是能够在鸿蒙 PC 上完成真实文件编辑、搜索、编码处理和会话管理的原生 HAP 应用。

对于其他重度依赖 Win32 的 C++ 桌面软件,这套实践也提供了一条可复用的思路:先保住真正有价值的跨平台内核,再为新系统设计合适的外壳和系统边界。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐