news 2026/10/14 14:49:46

ModernFlyouts 开发者指南:从源码构建、打包到本地调试的完整实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ModernFlyouts 开发者指南:从源码构建、打包到本地调试的完整实战

【免费下载链接】ModernFlyouts

A modern Fluent Design replacement for the old Metro themed flyouts present in Windows.

项目地址:https://gitcode.com/gh_mirrors/mo/ModernFlyouts
点击查看免费下载

ModernFlyouts 是一个基于 Fluent Design 的开源 Windows 通知浮窗(Flyout)替代方案,用来替换 Windows 内置的旧版 Metro 风格音量、亮度、飞行模式浮窗。本文是一份面向开发者的构建与测试指南,围绕仓库中的 docs/developer_guide.md 展开,结合源码结构讲解如何在 Visual Studio 2019 中完成环境配置、克隆仓库、构建 MSIX 打包工程并启动调试。读完本文,你将掌握 ModernFlyouts 完整的本地开发闭环:能独立从源码产出可安装的测试包,并能区分主工程与打包工程的职责,避免踩中"运行假应用""覆盖正式安装"等常见坑。

一、仓库概览:五个工程各司其职

在动手构建之前,先理解仓库的解决方案结构。仓库根目录的 ModernFlyouts.sln 定义了 5 个工程,各平台(x86/x64/arm64)与配置(Debug/Release)的组合均在解决方案配置中声明:

工程类型职责
ModernFlyoutsWPF(.NET 6)主应用,包含全部应用层源码(ModernFlyouts.csproj)
ModernFlyouts.Core类库(.NET 6)核心逻辑:媒体会话、显示器管理、原生浮窗互操作等(ModernFlyouts.Core.csproj)
ModernFlyouts.PackageMSIX 打包工程(WAP)将应用打包为 APPX/MSIX,是唯一需要"运行"的工程(ModernFlyouts.Package.wapproj)
ModernFlyoutsBridgeC++ DLL原生桥接层,借助 hostfxr 加载 .NET Core 运行时(dllmain.cpp)
ModernFlyoutsHostC++ 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工程下),按以下步骤操作:

  1. Application 选项卡:把Display Name从ModernFlyouts (Preview)改成其他名称,例如ModernFlyouts (Dev),用于区分正式安装与本次测试构建。
  2. Packaging 选项卡(原文档标注为"!!!Important!!!"):
    • 把Package name从32669SamG.ModernFlyouts改为类似(YourName).ModernFlyouts的自定义名称;
    • 把Package display name从ModernFlyouts (Preview)改为ModernFlyouts (Dev)。
    • 这一步能防止测试构建覆盖你机器上已正式安装的 ModernFlyouts,因为 MSIX 以包标识(Package Identity)区分应用。
  3. 选择证书:点击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

原文档给出了两条硬性规则:

  1. 永远不要直接运行ModernFlyouts工程——它会启动一个"无应用数据支持的哑应用(dummy app)",无法正常读写设置与应用数据。
  2. 务必运行ModernFlyouts.Package工程;如果机器上已预装 ModernFlyouts,请先关闭它再运行本次测试构建(否则可能与正式版本互相干扰)。

运行步骤:

  1. 确保ModernFlyouts.Package是 Startup Project。
  2. 点击工具栏的▶ 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.

项目地址:https://gitcode.com/gh_mirrors/mo/ModernFlyouts
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/14 14:49:16

Linux静态库与共享库

库&#xff1a;预先编译好的方法的集合静态库libxx.a原理&#xff1a;把要用的方法赋值一遍&#xff0c;所以删除之后不会影响头文件&#xff1a;库函数的声明&#xff1b;位置&#xff1a;/usr/include/stdio.h库文件&#xff1a;库函数的实现构建库&#xff1a;gcc -c add.c;…

作者头像 李华
网站建设 2026/10/14 14:48:01

ClickStack 2026年1月版:实时协作与AI开发增强解析

1. ClickStack 2026年1月版核心更新解析作为持续跟踪ClickStack技术栈的开发者&#xff0c;刚体验完2026年1月版本更新后&#xff0c;必须说这次迭代在性能优化和开发体验上带来了显著提升。这个面向全栈开发者的低代码平台&#xff0c;本月重点强化了实时协作、AI辅助和云原生…

作者头像 李华
网站建设 2026/10/14 14:47:41

T3 Stack实战:从零构建类型安全的短链接全栈应用

那段时间我特别烦一件事&#xff1a;手上的短链接需求明明逻辑很简单&#xff0c;却要在 Next.js 里自己搭接口、写类型定义&#xff0c;前端再手搓一套对应的请求函数。改一个字段&#xff0c;前后端类型对不上&#xff0c;跑起来才报错。后来我重新开了个项目&#xff0c;代号…

作者头像 李华
网站建设 2026/10/14 14:46:38

现代C++库设计:值语义与类型擦除的实践指南

1. 为什么我们需要重新思考C库设计十年前我刚参与一个大型C项目时&#xff0c;被代码库的状态震惊了——到处是裸露的new/delete、难以追踪的生命周期、接口参数五花八门。更可怕的是&#xff0c;修改某个"工具类"会导致十几处看似无关的模块崩溃。这就是典型的"…

作者头像 李华