WinMerge 鸿蒙 PC 适配全记录:以 Qt 重建桌面外壳,打通文件与文件夹差异闭环
欢迎加入开源鸿蒙 PC 社区:https://harmonypc.csdn.net/
欢迎在 PC 社区平台申请新建项目:https://atomgit.com/OpenHarmonyPCDeveloper
适配开源地址:https://atomgit.com/OpenHarmonyPCDeveloper/ohos_winmerge
环境搭建文章:https://blog.csdn.net/weixin_52908342/article/details/161343743
一、为什么要适配 WinMerge
WinMerge 是 Windows 平台上使用非常广泛的文件与目录比较工具。开发者排查配置差异、审阅补丁、核对构建产物,运维人员检查环境文件,内容团队比对多版本文本时,都会遇到“两个目录看起来差不多,但究竟改了什么”的问题。和只输出一段补丁的命令行工具相比,WinMerge 的价值在于把差异定位、内容核对和左右同步放在同一个桌面工作流里。
HarmonyOS PC 已经能够承载越来越多的生产力应用,但文件比较工具不仅要把界面显示出来,还必须处理桌面文件选择、目录递归、编码识别、修改写回和持久授权等系统边界。选择 WinMerge 做适配,一方面是希望补齐这一类高频工具,另一方面也是想验证:一个长期依赖 Win32/MFC 的成熟 C++ 项目,能否在保留使用习惯的前提下,形成一套真正适合鸿蒙 PC 的实现。
本次适配以 WinMerge 2.16.57.0 为基线,鸿蒙应用包名为 org.winmerge.harmony,目标设备覆盖 2in1 与 tablet,Native 架构为 arm64-v8a。
二、先确定迁移边界:不能把 MFC 工程直接搬过来
WinMerge 上游的主窗口、消息分发、资源系统、Shell Extension、COM、注册表以及插件装载都与 Windows 桌面环境深度绑定。即使逐个解决头文件和编译错误,也无法自然获得鸿蒙上的窗口、文件授权和应用生命周期。继续沿用原有 MFC 外壳,会把适配工作变成长期维护一套不完整的 Win32 兼容层。
因此,项目没有追求“让原 Windows 工程原封不动通过编译”,而是先划分能力边界:
| 层次 | 原项目形态 | 鸿蒙侧处理方式 |
|---|---|---|
| 系统入口 | Win32 进程与消息循环 | Stage 模型的 EntryAbility |
| 桌面界面 | MFC 菜单、工具栏和视图 | Qt Widgets 重建高频交互 |
| 文件访问 | Windows 路径与 Shell | 鸿蒙文件选择器与持久授权 |
| 文本比较 | 原生比较链路 | 前后缀裁剪、LCS 对齐与差异块模型 |
| 目录比较 | Windows 文件系统遍历 | Qt 递归扫描、过滤与 SHA-256 判同 |
| Windows 集成 | Shell Extension、COM、注册表 | 当前版本不移植,按鸿蒙能力重新设计 |
这条路线的取舍很明确:保留 WinMerge 的双栏比较、差异导航、左右同步和报告导出习惯,但不伪装成原版全部功能已经迁移。首先把日常最常用的文本与文件夹比较做成可安装、可读写、可持续维护的鸿蒙 PC 应用。
三、鸿蒙版本的整体架构
鸿蒙工程位于仓库根目录的 harmony_pc/。ArkTS 负责 Ability 生命周期和页面宿主,XComponent 提供 Native 图形承载面,Qt for OpenHarmony 的 QPA 插件把 Qt 窗口接入系统,最终由 libentry.so 运行 WinMerge 的 Qt Widgets 桌面外壳。
EntryAbility
└── Index.ets / XComponent
└── Qt for OpenHarmony QPA
└── libentry.so
├── WinMerge 风格菜单与工具栏
├── 文本双栏比较与差异块导航
├── 文件夹递归比较与过滤
├── 左右同步、保存与报告导出
└── 最近记录和比较选项持久化
工程中的关键目录如下:
ohos_winmerge/
├── Src/ # 上游 WinMerge / MFC 源码
├── README.OpenHarmony_CN.md # 鸿蒙侧构建与能力说明
└── harmony_pc/
├── AppScope/app.json5 # 包名、版本、图标与应用名
├── build-profile.json5 # SDK、产品与签名配置
├── qtforharmony_sdk/ # Qt for OpenHarmony SDK
└── entry/src/main/
├── ets/ # Ability 与 XComponent 宿主
├── module.json5 # 设备类型、权限与模块声明
└── cpp/
├── CMakeLists.txt # Native 构建入口
└── winmerge_ohos_shell.cpp # Qt 外壳与比较主流程
四、从文件选择开始建立完整工作流
1. 接入鸿蒙文件选择器,而不是依赖普通路径输入
桌面比较工具的第一步看似只是选择两个路径,实际涉及文件与文件夹两种选择模式、只读标记、三方路径入口、目录过滤和子目录开关。鸿蒙版本保留了 WinMerge 熟悉的打开页,并通过 Qt for OpenHarmony 的原生选择器接入系统授权流程。
以下五张图片均来自 HarmonyOS PC 2in1 真机实际运行画面。测试设备截图分辨率为 3120×2080,运行包为本项目生成并安装的 arm64-v8a 签名 HAP。图中的文件与目录均由系统选择器真实授权后打开。

应用在成功打开路径后调用文件共享接口持久化授权,后续启动时再激活已有权限。这样“最近文件”与 .WinMerge 项目才不只是保存两段字符串,而是真正能够在冷启动后恢复比较。目标路径还可以分别标记为只读;执行同步前会再次检查,避免误写重要文件。
2. 文本比较必须同时解决对齐、编码和展示
文本读取阶段会识别 UTF-8、带 BOM 的 UTF-8、UTF-16 LE/BE,并在 UTF-8 解码失败时尝试 GB18030;换行符则统一进入内部模型,再在摘要中显示原文件的编码与 LF/CRLF 状态。二进制文件通过零字节探测识别,不会直接作为乱码塞进文本表格。
差异算法先裁掉完全一致的前缀和后缀,再对中间区间执行 LCS 对齐,将结果整理为相同、左侧独有、右侧独有和内容变化四种行状态。对于过大的比较区间,工程设置了内存门限并退化为按位置配对,避免一次比较消耗不可控的内存。

左右表格共用同一份差异行模型。黄色表示内容变化,蓝色表示单侧存在;顶部摘要给出总行数、不同项与差异块数量。双击单元格可修改已有行,保存时按照目标文件原有编码、BOM 和换行符写回,避免一次简单编辑悄悄改变整个文件格式。
3. 差异导航与同步以“块”为单位
真实文件的差异往往连续出现。若只让用户逐行点击,很容易漏掉同一处修改的上下文。因此适配版会把连续非相同行聚合为差异块,支持上一处、下一处、第一处和最后一处导航,也保留 Alt+Up、Alt+Down、Alt+Home、Alt+End 快捷键。

“Copy to Right”和“Copy to Left”同样以差异块为单位工作。写入后立即重新比较,并尽量定位到下一处差异。这样用户能够沿着“定位—核对—同步—复查”的顺序完成合并,而不是执行一次复制后还要手工刷新整个视图。
4. 比较选项要进入算法,而不是停留在界面
不同团队对文本差异的判定标准并不相同。代码审阅通常关心大小写和空白,配置核对则可能只关心字段值。当前版本提供忽略大小写、忽略全部空白、忽略空白变化和忽略空行四项设置;设置由 QSettings 持久化,并在文本归一化阶段真正参与比较。

其中“忽略全部空白”和“忽略空白变化”具有互斥语义:前者移除所有空白字符,后者只把连续空白归一化。将规则放在比较模型之前处理,可以保证摘要、颜色、差异导航和同步判断使用同一套结果。
5. 文件夹比较需要可解释,也需要可操作
目录比较使用相对路径合并左右文件集合,支持 *.cpp;*.h 这类多模式过滤和递归开关。两侧都存在的文件先比较大小,再计算 SHA-256;最终结果分为相同、内容不同、仅左侧存在和仅右侧存在。扫描过程提供进度提示与取消入口,避免大目录长时间占用界面。

结果表不仅显示文件名,还给出相对目录、比较结论、左右修改时间、扩展名和文件大小。选中条目后可以执行左右复制;若源侧不存在而目标侧存在,则会在明确确认后删除目标文件。每次操作完成都会重新扫描,使表格始终反映磁盘上的当前状态。
五、适配过程中最棘手的几个问题
难点一:MFC 外壳与业务能力缠得很紧
WinMerge 并不是一个“换套 GUI 库就能运行”的项目。菜单命令、文档视图、Windows 消息和插件体系长期共同演进。适配初期最重要的工作不是写控件,而是明确首个鸿蒙版本必须闭环的场景:选择两个对象、看到可信差异、定位差异、左右同步、保存或导出。只有先收紧范围,Qt 外壳才不会演变成另一套难以维护的半成品 MFC。
难点二:沙箱授权决定了最近记录是否真的可用
在开发机上用普通绝对路径测试,很容易误以为文件读取已经解决。真机上的系统选择器返回受授权约束的路径;应用重启后如果没有持久化并重新激活权限,最近文件、最近项目和命令行二次唤起都会失效。因此,本项目把授权处理放在打开、比较、持久化和恢复链路中统一考虑,而不是只在选择按钮后做一次临时读取。
难点三:同步内容时不能破坏目标文件格式
将左侧文本转成 QString 再写到右侧很容易,但如果固定使用 UTF-8/LF,GB18030 或 UTF-16 文件会被悄悄改写。适配版为两侧分别保存编码、BOM 与换行符信息,差异块复制后使用目标侧格式编码。这种实现比“界面上能看到中文”多走了一步,却是比较工具敢于执行写操作的基础。
难点四:Qt 窗口生命周期要与 Ability 对齐
应用由 ArkTS 创建页面,再通过 NODE 类型 XComponent 启动 Qt。Ability 前后台切换、窗口创建和 Qt 主事件循环之间存在明确时序;QPA 插件与 libentry.so 也必须随 HAP 一起进入 arm64-v8a 产物。工程将 ArkTS 保持为轻量宿主,把桌面交互集中在 Qt 层,减少两套 UI 状态相互同步的复杂度。
难点五:签名不是构建完成后的附属步骤
调试 Profile 与应用包名、设备信息和有效期绑定。当前包名为 org.winmerge.harmony,更换设备或包名后必须重新生成匹配的签名材料。只有完成签名、安装、系统选择器授权、文件读写和重启后的权限恢复,才能证明桌面工具真正完成了交付闭环。
六、构建、安装与启动
使用 DevEco Studio 时,打开仓库下的 harmony_pc/,确认 Qt for OpenHarmony SDK 路径有效,并为当前包名配置调试签名。命令行构建可执行:
cd harmony_pc
hvigorw --mode module -p module=entry assembleHap --no-daemon
构建产物位于:
harmony_pc/entry/build/default/outputs/default/
├── entry-default-unsigned.hap
└── entry-default-signed.hap
连接 HarmonyOS PC 后,可以安装并启动:
hdc list targets
hdc install -r harmony_pc/entry/build/default/outputs/default/entry-default-signed.hap
hdc shell aa start -b org.winmerge.harmony -a EntryAbility
本次文档整理前重新执行了 Native、ArkTS、HAP 打包和签名任务,构建成功;随后在已连接的 2in1 真机上安装并完成文件选择、文本比较、差异导航、比较选项和文件夹比较验证。当前签名 HAP 大小约 22 MB。
七、当前功能边界
当前版本已经覆盖日常比较工作的主线:
- 鸿蒙原生文件与文件夹选择、路径授权持久化;
- 双栏文本比较、行号、差异着色与差异块导航;
- UTF-8、UTF-16 LE/BE、GB18030 读取及原编码、原换行符写回;
- 已有行的行内修改、保存、只读保护与左右差异块同步;
- 递归文件夹比较、名称过滤、SHA-256 判同与左右文件同步;
- 比较选项、最近文件、最近项目、
.WinMerge项目读写; - 文本与文件夹比较报告导出。
尚未纳入当前版本的能力包括完整三方比较视图、图片/表格/网页专用比较器、原版插件与 Prediffer/Unpacker 体系、Windows Shell Extension、COM 和注册表集成,以及可增删行的完整文本编辑体验。菜单中部分入口用于保持信息架构,但触发时会明确提示当前鸿蒙版本尚未实现,不会把占位入口描述成已经可用的功能。
因此,现阶段更准确的定位是“WinMerge HarmonyOS PC 日常可用版”:它能够完成真实文件与目录的选择、比较、导航、同步和报告导出,但并不是 Windows 版所有高级模块的逐项复制。
八、总结
WinMerge 的适配说明,传统 Windows 桌面软件迁移到 HarmonyOS PC,关键并不是消灭所有平台差异,而是重新判断哪些能力值得保留、哪些边界必须重建。
本项目使用 Stage 模型与 XComponent 接住鸿蒙应用生命周期,通过 Qt for OpenHarmony 重建桌面交互,再围绕系统文件选择、持久授权、编码保持、差异块和目录同步补齐完整工作流。最终得到的不是只能展示首页的演示程序,而是一款能够在真机上处理真实文件、解释比较结果并安全写回的桌面工具。
对于其他依赖 MFC、Win32 或系统 Shell 的 C++ 项目,这套实践也提供了一个可复用的顺序:先定义用户真正需要的核心闭环,再替换平台外壳,最后用真机文件访问和写回结果验证每一条能力。
更多推荐



所有评论(0)