【免费下载链接】ModernFlyouts
A modern Fluent Design replacement for the old Metro themed flyouts present in Windows.
ModernFlyouts 是一个基于 Fluent Design 的开源 Windows 通知浮窗(Flyout)替代方案,用来替换 Windows 内置的旧版 Metro 风格音量、亮度、飞行模式浮窗。本文是一份面向开发者的构建与测试指南,围绕仓库中的 docs/developer_guide.md 展开,结合源码结构讲解如何在 Visual Studio 2019 中完成环境配置、克隆仓库、构建 MSIX 打包工程并启动调试。读完本文,你将掌握 ModernFlyouts 完整的本地开发闭环:能独立从源码产出可安装的测试包,并能区分主工程与打包工程的职责,避免踩中"运行假应用""覆盖正式安装"等常见坑。
一、仓库概览:五个工程各司其职
在动手构建之前,先理解仓库的解决方案结构。仓库根目录的 ModernFlyouts.sln 定义了 5 个工程,各平台(x86/x64/arm64)与配置(Debug/Release)的组合均在解决方案配置中声明:
| 工程 | 类型 | 职责 |
|---|---|---|
ModernFlyouts | WPF(.NET 6) | 主应用,包含全部应用层源码(ModernFlyouts.csproj) |
ModernFlyouts.Core | 类库(.NET 6) | 核心逻辑:媒体会话、显示器管理、原生浮窗互操作等(ModernFlyouts.Core.csproj) |
ModernFlyouts.Package | MSIX 打包工程(WAP) | 将应用打包为 APPX/MSIX,是唯一需要"运行"的工程(ModernFlyouts.Package.wapproj) |
ModernFlyoutsBridge | C++ DLL | 原生桥接层,借助 hostfxr 加载 .NET Core 运行时(dllmain.cpp) |
ModernFlyoutsHost | C++ EXE | 启动宿主,作为开机启动任务拉起主程序(ModernFlyoutsHost.vcxproj) |
关键点:主应用源码全部集中在ModernFlyouts工程,但构建与运行的目标必须是ModernFlyouts.Package工程。打包工程通过ProjectReference引用ModernFlyouts与ModernFlyoutsHost,并把Package.appxmanifest作为清单文件(见 ModernFlyouts.Package.wapproj),因此构建它即可产出完整可安装的包。
二、前置条件:系统与 Visual Studio 环境
2.1 系统要求
原文档给出的推荐环境为:
- Windows 10 20H2 或更新的 Insider 预览版(推荐)。
- 至少4 GB 内存与x64 架构 CPU(推荐)。
- (可选)任意 Git 客户端,如 Git for Windows 或 GitHub Desktop;项目推荐初学者直接使用Visual Studio 的 GitHub Extension。
从仓库实际声明看,构建期目标平台为TargetPlatformVersion 10.0.19041.0、最低TargetPlatformMinVersion 10.0.17763.0(见 ModernFlyouts.Package.wapproj),且 Package.appxmanifest 中TargetDeviceFamily的MinVersion="10.0.17763.0"(Windows 10 1809)、MaxVersionTested="10.0.19041.0"(Windows 10 2004)。README 亦声明支持 Windows 10 1809 及以上与 Windows 11。因此,20H2 是开发调试的稳妥选择,但低于 1809 的系统将无法安装产物。
2.2 Visual Studio 工作负载
安装最新版 VS2019(稳定版或预览版均可),并务必勾选以下工作负载/组件:
- .NET desktop development(.NET 桌面开发)——编译 C# / WPF 工程。
- Desktop development with C++(使用 C++ 的桌面开发)——编译
ModernFlyoutsBridge与ModernFlyoutsHost两个 C++ 工程。 - MSIX Packaging Tools(MSIX 打包工具)——打包工程
ModernFlyouts.Package依赖此组件才能编译。 - GitHub Extension for Visual Studio(推荐)——方便直接在 IDE 内克隆仓库与提交代码。
需要说明的是,当前仓库主工程已迁移到 .NET 6(TargetFramework net6.0-windows10.0.19041.0,见 ModernFlyouts.csproj),构建时还需安装对应的 .NET 6 SDK / 开发包;C++ 工程使用PlatformToolset v142(见 ModernFlyoutsHost.vcxproj),这正是 VS2019 的默认工具集。
三、克隆仓库并打开解决方案
克隆方式不限:可以使用任意 Git 客户端,也可以在 Visual Studio 中通过Clone a repository直接克隆,甚至可以用 GitHub 的Download Code as ZIP下载后解压。
克隆完成后,在 VS2019 中打开解决方案文件ModernFlyouts.sln。若使用命令行克隆,示例为:
git clone <仓库地址> ModernFlyouts随后用 VS2019 打开ModernFlyouts/ModernFlyouts.sln即可。首次打开时 VS 会自动触发 NuGet 还原;若未自动还原,可在解决方案上右键选择"还原 NuGet 包"。
四、构建项目:真正要构建的是 ModernFlyouts.Package
4.1 先设置解决方案配置
原文档强调:构建前务必在 Visual Studio 的 Configuration Manager 中,将 Active Solution Configuration 设为 Debug,Active Solution Platform 设为 x64。这保证了调试符号可用、并匹配宿主/桥接工程的原生二进制(ModernFlyoutsHost_x64.exe等预置二进制位于 ModernFlyoutsHost 目录下)。
4.2 为什么必须构建 Package 工程
ModernFlyouts工程虽然包含全部应用源码,但它是一个裸 WPF 主程序,脱离打包工程运行时没有 MSIX 环境提供的应用数据(ApplicationData)、启动任务等能力。原文档明确指出:
真正需要构建的是
ModernFlyouts.Package工程——它负责把应用打包并正确运行。
从 Program.cs 可以看到,应用启动时依赖AppDataMigration.Perform()迁移应用数据、NativeFlyoutHandler初始化等流程,这些逻辑在完整打包环境下才可靠。因此日常开发一律以ModernFlyouts.Package为构建目标。
4.3 构建前必须修改清单:防止覆盖正式安装
在构建ModernFlyouts.Package之前,需要打开 Package.appxmanifest(位于ModernFlyouts.Package工程下),按以下步骤操作:
- Application 选项卡:把Display Name从
ModernFlyouts (Preview)改成其他名称,例如ModernFlyouts (Dev),用于区分正式安装与本次测试构建。 - Packaging 选项卡(原文档标注为"!!!Important!!!"):
- 把Package name从
32669SamG.ModernFlyouts改为类似(YourName).ModernFlyouts的自定义名称; - 把Package display name从
ModernFlyouts (Preview)改为ModernFlyouts (Dev)。 - 这一步能防止测试构建覆盖你机器上已正式安装的 ModernFlyouts,因为 MSIX 以包标识(Package Identity)区分应用。
- 把Package name从
- 选择证书:点击Publisher文本框旁的Choose Certificate按钮:
- 方式一:在 "Choose a Certificate" 对话框中点Select from store,下一步直接Ok(使用现有证书);
- 方式二:点Create,在下一步对话框中输入你的名字,然后Ok(生成临时自签名证书)。
仓库中Package.appxmanifest的<Identity>节点也印证了默认包名为32669SamG.ModernFlyouts、发布者为CN=samue(见 Package.appxmanifest),版本号由AppxAutoIncrementPackageRevision自动递增(见 ModernFlyouts.Package.wapproj)。
4.4 执行构建
配置完成后,将ModernFlyouts.Package设为Startup Project,然后选择Build > Build ModernFlyouts.Package,或直接按Ctrl+B。
构建完成后,产物为 MSIX/APPX 包(含 x86/x64/arm64 三种平台架构的 bundle,由AppxBundlePlatforms指定,见 ModernFlyouts.Package.wapproj),可直接部署到本机或其他开发机测试。
4.5 提交代码时的注意事项
重要:向仓库提交变更时,不要包含对ModernFlyouts.Package.wapproj和Package.appxmanifest的修改。这两份文件属于你本地的开发环境配置(包名、证书等),不应污染公共仓库。这与 CI 的做法一致——azure-pipelines.yml 中的流水线会在构建时动态改写 manifest 的 Publisher 与 DisplayName,说明 manifest 应由构建流程统一管理。
五、运行与调试:F5 启动的是 Package,不是 ModernFlyouts
原文档给出了两条硬性规则:
- 永远不要直接运行
ModernFlyouts工程——它会启动一个"无应用数据支持的哑应用(dummy app)",无法正常读写设置与应用数据。 - 务必运行
ModernFlyouts.Package工程;如果机器上已预装 ModernFlyouts,请先关闭它再运行本次测试构建(否则可能与正式版本互相干扰)。
运行步骤:
- 确保ModernFlyouts.Package是 Startup Project。
- 点击工具栏的▶ Local Machine按钮,或菜单Debug > Start Debugging,或按F5。
启动后,应用会通过宿主程序拉起主进程。这一过程从源码中可以清晰看到:
- Program.cs 的入口
Main创建 STA 线程,调用AppLifecycleManager.StartApplication完成单实例检查与命令行参数转发,随后初始化NativeFlyoutHandler、本地化,并new App().Run(); - App.xaml.cs 在
App_Startup中创建FlyoutHandler并调用Initialize(); - FlyoutHandler.cs 的
Initialize依次初始化DisplayManager、UIManager、创建FlyoutWindow、挂载NativeFlyoutHandler事件、KeyboardHook,最后创建音频/飞行模式/锁键/亮度四个FlyoutHelper并订阅ShowFlyoutRequested。
5.1 单实例与命令行参数
AppLifecycleManager.cs 使用命名互斥体(Mutex)+ 命名管道(NamedPipe)实现单实例:重复启动时,后续实例会把命令行参数通过管道转发给首个实例后自行退出。应用支持以下参数(定义于 JumpListHelper.cs,解析于 AppLifecycleManager.cs):
| 参数 | 含义 |
|---|---|
/settings | 打开设置窗口 |
/restore | 恢复默认(重建原生浮窗后安全退出) |
/exit-safe | 安全退出应用 |
/app-restarted-after-update | 更新后重启通知(当前为空实现) |
5.2 原生浮窗的拦截原理(调试时值得了解)
ModernFlyouts的核心能力来自对 Windows 原生浮窗的"接管"。NativeFlyoutHandler.cs 通过SetWinEventHook监听 shell 进程中NativeHWNDHost窗口的创建/显示/销毁事件,一旦捕获到原生浮窗出现,FlyoutHandler会决定隐藏原生浮窗并代之以自己的FlyoutWindow(见 FlyoutHandler.cs)。调试时若发现浮窗未弹出或出现双浮窗,可优先检查这一事件链路是否被其他软件干扰。
六、常见问题与排查建议
| 现象 | 可能原因 | 处理 |
|---|---|---|
| 编译报错缺少 MSIX 打包组件 | 未安装 MSIX Packaging Tools 工作负载 | 回到 VS Installer 补装组件 |
| C++ 工程编译失败 | 缺少 C++ 桌面开发工作负载,或工具集版本不符 | 确认安装 "Desktop development with C++"(v142 工具集) |
| 安装测试包后正式版被覆盖 | 未修改Package.appxmanifest中的 Package name | 按 4.3 节改成自定义包名 |
直接运行ModernFlyouts工程出现异常 | 裸工程缺少 MSIX 应用数据环境 | 改为以ModernFlyouts.Package启动 |
| 浮窗不显示或行为异常 | 原生浮窗事件钩子未生效(如被安全软件拦截) | 关闭冲突软件后重启应用,必要时用/restore参数重置 |
七、延伸:发布构建与 CI 参考
如需产出正式发布包,仓库提供了三份发布配置(SelfContained+ 单文件发布):
- win10-x64.pubxml
- win10-x86.pubxml
- win10-arm64.pubxml
它们由打包工程在构建时按平台选择(见 ModernFlyouts.Package.wapproj)。此外,azure-pipelines.yml 展示了官方 CI 的做法:NuGetCommand还原包 → PowerShell 改写 manifest(Publisher、DisplayName)→MSBuild构建ModernFlyouts.Package并产出 appxupload 包。本地开发虽不需要完整 CI,但其中的"构建前动态调整 manifest"思路与 4.3 节"本地改包名防覆盖"一脉相承。
至此,你已经具备了从零构建 ModernFlyouts 测试包、正确启动调试以及理解应用启动链路的完整能力。后续深入开发时,可继续阅读 docs/developer_guide.md 之外的相关文档(如 docs/GSMTC-Support-And-Popular-Apps.md)了解媒体会话支持范围,或对照 README.md 了解功能特性与系统要求。
【免费下载链接】ModernFlyouts
A modern Fluent Design replacement for the old Metro themed flyouts present in Windows.
相关推荐
OpenMTP 开发指南:从源码构建、本地调试到 macOS 打包发布的全流程实践
OpenMTP 开发指南:从源码构建、本地调试到 macOS 打包发布的全流程实践 导读 DEVELOPMENT.md https://link.gitcode
桌面应用Angular CLI 源码仓库开发者指南:从本地构建、调试到测试的完整工作流
Angular CLI 源码仓库开发者指南:从本地构建、调试到测试的完整工作流 本篇指南围绕当前开源仓库(angular cli,即 Angular CLI 与
CLI开发工具前端构建构建工具代码生成前端Fleet 开源贡献者指南:从源码构建、本地开发到测试与调试的完整入门手册
Fleet 开源贡献者指南:从源码构建、本地开发到测试与调试的完整入门手册 Fleet 是一个开源设备管理平台(Open device management),
后端前端企业应用运维网络安全
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考