—— Windows 平台开发知识培训 · 从 Win32 到 WinUI 3 ——

Windows 的修炼之道

小哲的公司后端和 Android 都有了——老板又要做 Windows 桌面端:给运营的效率工具、给客户的桌面客户端。小哲没写过桌面应用,周师傅说:Windows 是个「四十年的江湖」,技术栈从 C 的 Win32 一路进化到 C# 的 WinUI 3,选对栈、懂消息循环、会打包签名,才算入门。这一本,从系统架构讲到上架分发。

🪟 🧱 🗺️ 💠 🖥️ ✨ 🗄️ 🔀 📦 🛡️ 🚀
序 章

桌面端的江湖

Windows 开发全景:系统 + 语言 + UI + 分发
🧑‍💻
小哲

师傅!老板要我们做 Windows 桌面端——运营效率工具 + 给客户的桌面客户端。我写过 Web 和 Android,桌面端要从哪学起?听同事说什么 Win32、WPF、WinUI……好乱!

🧙
周师傅

乱就对了——Windows 有 40 年历史,技术栈「层层叠叠」:老的还在用、新的不断出。先给你一张「地图」,再带你逐层点亮:

  • 系统层:Win32 API、消息循环——Windows 一切的地基(懂它,什么都懂了)。
  • 语言层:C# + .NET——现代 Windows 开发的绝对主力。
  • UI 层:WPF(经典王者)→ WinUI 3(新方向)→ .NET MAUI(跨平台)。
  • 工程层:Visual Studio、打包、签名、分发——桌面开发的规矩。

来,十站路线——

1
平台架构NT 内核、Win32 API、消息循环、句柄
2
技术栈演进Win32→MFC→WPF→UWP→WinUI 3→MAUI/Qt/Electron
3
C# 与 .NETCLR、GC、LINQ、async/await、NuGet
4
WPFXAML、数据绑定、MVVM、Dispatcher——桌面经典
5
WinUI 3Fluent Design、Windows App SDK、MSIX——新方向
6
数据层文件 IO、EF Core/SQLite、配置、JSON
7
并发异步UI 线程、Dispatcher、async/await、Task
8
工程化Visual Studio、NuGet、测试、打包 MSIX、自动更新
9
系统集成P/Invoke、注册表、Windows 服务、托盘、文件关联
10
安全质量UAC、代码签名、SmartScreen、崩溃监控、兼容
🧙
周师傅

记住一句话:Windows 开发 = 懂系统(消息循环/句柄)+ 选对栈(场景匹配)+ C# 打底 + 会打包签名。走,第一站,先把「地基」挖开。

第 1 站

平台架构:系统怎么组织

NT 内核 · Win32 API · 消息循环 · 句柄 · 进程线程

Web 和 Android 都有「平台底层」——Windows 的底层是 Win32 API + 消息循环。理解它,你就理解了「为什么 Windows 程序长这样」。

🧙
周师傅

Windows 平台四层:

  • NT 内核:地基——进程/线程/内存管理(和 Linux 内核是「两个门派」)。
  • Win32 API:系统给程序提供的「函数库」——创建窗口、画界面、读文件全靠它(C 语言时代的遗产,现在还在)。
  • 消息循环(消息泵):Windows 程序的「心脏」——鼠标点一下、键盘敲一下,都变成「消息」发给窗口;程序循环取消息、处理消息。这是桌面 UI 和 Web 最大的不同!
  • 句柄(Handle):窗口/文件/进程的「身份证号」——一切资源都用句柄操作。

还有两个概念:用户模式 vs 内核模式(程序不能直接碰硬件,要过 API 这道门——安全设计)、注册表(系统配置的「大字典」)、Windows 服务(开机自启的后台程序)。

Win32 程序的生命:消息循环
【一个 Win32 程序(C 语言,最底层的样子)】
WinMain()
  ① 注册窗口类(告诉系统窗口长啥样)
  ② 创建窗口(CreateWindow → 拿到句柄 HWND)
  ③ 进入消息循环:
     while (GetMessage(&msg)) {
         TranslateMessage(&msg);   // 翻译键盘消息
         DispatchMessage(&msg);    // 派发给窗口函数
     }
  ④ 窗口函数处理消息(WndProc):
     点鼠标  → WM_LBUTTONDOWN → 处理
     画窗口  → WM_PAINT       → 画内容
     关窗口  → WM_CLOSE       → 退出循环

【为什么懂它很重要】
  一切 Windows UI 框架(WPF/WinUI)底层都是它
  消息循环 → 理解「UI 必须单线程」的根源(第7站)
  句柄 → 资源管理的概念(关闭句柄防泄漏)

【现代开发还需要 C 写 Win32 吗?】
  不需要!现代框架全封装了——但「懂原理」帮你理解
  为什么 Dispatcher 必须这样用、为什么 UI 卡顿

【用户模式 vs 内核模式】
  程序不能直接操作硬件/内核数据
  一切通过 Win32 API(系统调用)——安全边界

平台术语

  • NT 内核:Windows 的底层——进程/线程/内存管理。
  • Win32 API:系统函数库——程序的「系统接口」。
  • 消息循环:事件驱动的泵——Windows 程序的心脏。
  • 句柄(Handle):资源的「身份证号」——窗口/文件/进程。
  • 用户/内核模式:程序与内核的安全边界。
  • 注册表:系统配置的大字典——软件配置常存这。
  • Windows 服务:开机自启的后台程序(无界面)。

本站收获:平台地基 = Win32 API(系统接口)+ 消息循环(事件驱动的心脏)+ 句柄(资源身份证)。现代开发不直接写它,但「消息循环 → UI 单线程」这条因果链,是一切桌面 UI 的根源。

第 2 站

技术栈演进:选型地图

Win32 · MFC · WPF · UWP · WinUI 3 · MAUI · Qt · Electron

「Windows 开发用什么技术?」——答案是一张「历史地图」。40 年演进的每一代都还在江湖上活着,选型全看场景。

🧙
周师傅

按时间线认识「家族成员」:

  • Win32(C):祖宗——直接调 API,性能极致但开发慢(今天:驱动、底层工具、老系统维护)。
  • MFC(C++):Win32 的 C++ 封装——老一代桌面软件的主力(维护老项目会碰到)。
  • WPF(C#/XAML):2006 年至今的「经典王者」——声明式 UI + 数据绑定,企业桌面软件的主流。
  • UWP(C#):微软推的「商店化」尝试——生态没起来,基本退场(了解即可)。
  • WinUI 3(C#):新方向——现代 Fluent 设计 + 桌面原生能力,微软官方力推。
  • .NET MAUI(C#):跨平台(Windows/Mac/iOS/Android)——一套代码多端。
  • Qt(C++/QML):跨平台 C++ 框架——专业软件(CAD/工业)常见。
  • Electron(Web):用 HTML/CSS/JS 做桌面——VS Code/钉钉都是它,重但开发快。
选型地图:按场景挑栈
【技术栈家族树】
  原生(性能/系统能力):
    C/Win32   → 底层工具、驱动、极老系统
    C++/MFC   → 老桌面软件维护
    C#/WPF    → 企业桌面软件(现在的主流!)
    C#/WinUI3 → 新桌面应用(微软力推的新方向)
  跨平台:
    C#/.NET MAUI → 一套代码多端(Win/Mac/iOS/Android)
    C++/Qt      → 专业软件(CAD/工业/嵌入式)
   Web 技术:
    Electron    → 重 UI 应用、快速开发(VS Code/钉钉)
    Tauri       → 轻量 Electron 替代(Rust 后端,新宠)

【选型决策(按场景)】
  企业内部工具(轻量)   → WPF 或 WinUI 3
  企业级桌面产品         → WPF(生态最成熟)
  新桌面应用             → WinUI 3(微软力推)
  需要跨平台(含手机)   → .NET MAUI / Qt / Electron
  已有 Web 团队          → Electron / Tauri
  追求极致性能           → C++/Win32(或 Rust)

【学习建议】
  必学:C# + WPF(就业面最广、资料最多)
  关注:WinUI 3(未来方向)
  了解:MAUI / Electron(跨平台场景)

技术栈术语

  • Win32 / MFC:C/C++ 时代——底层但开发慢。
  • WPF:XAML + C#——2006 至今的桌面王者。
  • UWP:商店化尝试——基本退场。
  • WinUI 3:现代 Fluent + 原生能力——微软新方向。
  • .NET MAUI:一套 C# 代码多端(Win/Mac/手机)。
  • Qt / Electron / Tauri:跨平台 C++ / Web 技术 / 轻量 Web。
  • 选型口诀:企业桌面用 WPF,新应用看 WinUI 3,跨平台按团队选。

本站收获:技术栈地图 = Win32/MFC 是历史、WPF 是当下主流、WinUI 3 是未来、MAUI/Qt/Electron 是跨平台选项。先看懂地图,再选路——别一上来就纠结「学哪个」,先问「做什么」。

第 3 站

C# 与 .NET:现代主力

CLR · GC · LINQ · async/await · NuGet · 依赖注入

Windows 现代开发的语言是 C#,平台是 .NET——语法像 Java、写起来像 Kotlin 一样舒服,还有 LINQ 这种「查询神器」。有 Java/Kotlin 底子,C# 上手飞快。

🧙
周师傅

C# 六大看点:

  • CLR 运行时:C# 编译成 IL 中间语言,CLR 负责跑(GC 自动回收——第十四本 Java JVM 的「微软表亲」)。
  • 语法像 Java:类/接口/继承/泛型/异常——你在 Java 学的全能用上。
  • LINQ:查询语法——对集合「筛/排/投影」一行搞定(比 Java Stream 更顺)。
  • async/await:异步编程一等公民(第十六本协程、第四本 JS 同款思路)。
  • NuGet:包管理——.NET 世界的「pip/Maven」(第十六本老朋友)。
  • 依赖注入内置:.NET 自带 DI 容器——不用引第三方(第十四/十六本 IoC 老朋友)。
C# 速览(对照 Java/Kotlin 学)
// 类和属性(属性 = 字段+getter/setter 的语法糖)
public class User {
    public int Id { get; set; }          // 自动属性
    public string Name { get; set; } = "";
    public string? Phone { get; set; }   // 可空引用类型(Kotlin 空安全!)
}

// LINQ:查询集合(Java Stream / Kotlin 高阶函数的老朋友)
var adults = users
    .Where(u => u.Age >= 18)             // 筛选
    .OrderBy(u => u.Name)                // 排序
    .Select(u => u.Name)                 // 投影
    .ToList();

// async/await:异步(UI 不卡的关键,第7站展开)
public async Task<List<Order>> LoadOrdersAsync() {
    return await _api.GetOrdersAsync();  // 挂起不阻塞
}

// 依赖注入(.NET 内置)
builder.Services.AddSingleton<IOrderService, OrderService>();
builder.Services.AddTransient<MainWindow>();

【C# vs Java vs Kotlin(三兄弟对比)】
  语法:三者几乎同源(类/接口/泛型)
  C# 特色:LINQ、属性、async 一等公民
  Kotlin 特色:空安全、扩展函数、协程
  → 会任何一个,另两个上手都很快!

【.NET 版本(LTS 是王道,Java 同款哲学)】
  .NET 6/8(LTS):现役主流——新项目用 .NET 8
  每 11 月一个大版本——生产用 LTS

C# 术语

  • CLR / IL:运行时 / 中间语言——GC 自动管理内存。
  • 属性(Property):字段 + 访问器的语法糖——比 Java getter/setter 简洁。
  • 可空引用类型(?):C# 8+ 的空安全——Kotlin 同款思路。
  • LINQ:集合查询语法——Where/OrderBy/Select 链式调用。
  • async/await / Task:异步编程——UI 不卡的关键。
  • NuGet:包管理——.NET 生态的「应用商店」。
  • DI 内置:依赖注入容器——AddSingleton/AddTransient。

本站收获:C# = Java 语法底子 + Kotlin 的空安全 + LINQ 查询神器 + 内置 DI。会 Java/Kotlin 的你,C# 三天上手——.NET 就是「微软版的 Java 生态」。

第 4 站

WPF:桌面 UI 经典

XAML · 数据绑定 · MVVM · 控件 · Dispatcher

WPF 是 Windows 桌面软件的「常青树」——声明式 XAML 写界面、数据绑定驱动更新、MVVM 组织代码。Android 学过 Compose 的你,会觉得很亲切。

🧙
周师傅

WPF 四件套:

  • XAML:声明式 UI 语言——和 Android 的 Compose「同宗不同源」(都是声明式:界面 = 描述,不是命令)。
  • 数据绑定(Binding):界面和数据「自动同步」——数据变界面自动更新(状态驱动的 WPF 版)。
  • MVVM:ViewModel + 数据绑定——逻辑和界面彻底分离(第十七本 MVVM 完全同构!)。
  • Dispatcher:UI 线程的「调度员」——后台线程改 UI 必须通过它(消息循环的现代封装,第 1 站埋的梗在这收)。

控件生态:DataGrid(表格)、TreeView、TabControl……企业软件的「富控件」全都有。

WPF + MVVM 实战
<!-- XAML:声明式界面(对照 Android Compose)-->
<Window x:Class="Ledger.MainWindow" ...>
    <Grid Margin="20">
        <StackPanel>
            <TextBlock Text="{Binding TotalText}" 
                       FontSize="28" FontWeight="Bold"/>
            <DataGrid ItemsSource="{Binding Orders}" 
                      AutoGenerateColumns="False">
                <DataGridTextColumn Header="标题" Binding="{Binding Title}"/>
                <DataGridTextColumn Header="金额" Binding="{Binding Amount}"/>
            </DataGrid>
            <Button Content="刷新" Command="{Binding RefreshCommand}"/>
        </StackPanel>
    </Grid>
</Window>
// ViewModel:逻辑与界面分离(INotifyPropertyChanged 通知界面)
public class MainViewModel : INotifyPropertyChanged {
    public ObservableCollection<Order> Orders { get; } = new();

    private string _totalText = "合计 ¥0.00";
    public string TotalText {
        get => _totalText;
        set { _totalText = value; OnPropertyChanged(); }   // 通知界面更新
    }

    public ICommand RefreshCommand => new RelayCommand(async () => {
        var data = await _service.LoadAsync();             // 后台加载
        Orders.Clear();
        foreach (var o in data) Orders.Add(o);
    });
}

// Dispatcher:后台线程更新 UI 必须回 UI 线程
// (WPF 里 MVVM + 数据绑定自动处理大部分,手写时用 Dispatcher.Invoke)

【WPF vs Android Compose(对照学)】
  XAML(声明式)     ≈ Compose(声明式)
  数据绑定 Binding   ≈ 状态驱动(mutableStateOf)
  MVVM               ≈ MVVM(一模一样!)
  Dispatcher         ≈ 主线程限制(协程 Main dispatcher)
  → 学过 Compose 的人学 WPF 很快!

WPF 术语

  • XAML:声明式 UI 语言——界面即描述。
  • 数据绑定(Binding):界面数据自动同步——状态驱动。
  • MVVM:ViewModel + 绑定——职责分离(第十七本同款)。
  • INotifyPropertyChanged:属性变化通知——界面的「刷新信号」。
  • ICommand:命令模式——按钮动作绑到 ViewModel。
  • Dispatcher:UI 线程调度——后台改 UI 的入口。
  • 样式 / 模板 / 资源:控件外观的「CSS」——主题统一。

本站收获:WPF = XAML 声明式 + 数据绑定 + MVVM + Dispatcher。和第十七本 Compose 的 MVVM 完全同构——桌面端和移动端的架构,最后长成了同一个样子。

第 5 站

WinUI 3:新方向

Fluent Design · Windows App SDK · MSIX · 与 WPF 对比

WPF 是「经典王者」,但微软的新方向是 WinUI 3——现代 Fluent 设计 + 原生性能 + 桌面全能力。新项目怎么选?这一站讲清楚。

🧙
周师傅

WinUI 3 是什么:

  • Fluent Design:微软的现代设计语言——圆角、层次、动效、深色模式(对标 Material Design)。
  • Windows App SDK:WinUI 3 的「工具箱」——把系统能力(通知、存储、多窗口)统一打包,桌面应用想用啥有啥。
  • MSIX 打包:现代安装包格式——干净安装/卸载、自动更新、权限声明(对标 Android 的 App 包)。
  • XAML 语法同款:会 WPF 就会 WinUI 3——语法几乎一样,控件更现代。

对比 WPF:WinUI 3 界面更现代、微软持续投入;WPF 生态更成熟、老项目多。新项目建议 WinUI 3,企业存量维护继续 WPF。

WinUI 3 与选型决策
<!-- WinUI 3 XAML(和 WPF 同源,控件更现代)-->
<Window x:Class="Ledger.MainWindow" ...>
    <StackPanel Spacing="12" Padding="24">
        <TextBlock Text="本月支出" Style="{StaticResource TitleTextBlockStyle}"/>
        <InfoBar Message="支出超预算 20%!" IsOpen="True"
                 Severity="Warning"/>          <!-- Fluent 新控件 -->
        <ListView ItemsSource="{x:Bind ViewModel.Orders}">...</ListView>
        <Button Content="刷新" Command="{x:Bind ViewModel.Refresh}"/>
    </StackPanel>
</Window>

【Fluent Design 关键词】
  Mica/亚克力材质(半透明背景)、圆角、阴影层次
  深色/浅色主题自适应、流畅动效
  → 界面「现代感」的主要来源

【Windows App SDK 能力】
  系统通知(Toast)、多窗口、任务栏集成
  存储访问、桌面快捷方式、自动更新(App Installer)
  → 桌面应用的「系统级工具箱」

【MSIX 打包(现代分发)】
  干净安装/卸载(不留垃圾)、增量更新
  权限声明、企业批量部署支持
  → 替代老 InstallShield 的现代方案

【选型结论】
  新桌面应用   → WinUI 3(微软力推,现代)
  企业存量维护 → WPF(生态成熟,资料多)
  快速交付     → WPF 或 Electron(看团队)
  → 技能互通:XAML 学一次,两栈通吃

WinUI 3 术语

  • WinUI 3:现代 Windows 原生 UI 框架——微软新方向。
  • Fluent Design:微软设计语言——Mica 材质/圆角/动效。
  • Windows App SDK:桌面能力工具箱——通知/多窗口/存储。
  • MSIX:现代安装包格式——干净安装/自动更新。
  • InfoBar / NavigationView:Fluent 新控件——现代交互组件。
  • x:Bind:编译期绑定——比 Binding 更快。
  • 深色模式:主题自适应——现代应用的标配。

本站收获:WinUI 3 = Fluent 现代设计 + Windows App SDK 全能力 + MSIX 干净分发。XAML 学一次两栈通吃——新项目看 WinUI 3,存量维护靠 WPF,技能是通的。

第 6 站

数据层:文件与数据库

文件 IO · EF Core · SQLite · 配置 · JSON

桌面应用的数据住哪?——小数据用文件/JSON,结构化数据用 SQLite/EF Core,配置放 AppSettings。这一站,桌面端的数据层。

🧙
周师傅

数据层四件套:

  • 文件 IO:读写文件(文本/二进制/JSON)——导出报表、日志、配置。
  • EF Core:.NET 的 ORM——类映射表,自动迁移(第十六本 SQLAlchemy、第十四本 JPA 的 .NET 版)。
  • SQLite:桌面应用的事实数据库——单文件、免安装、零配置(手机 App 同款)。
  • 配置(AppSettings/JSON):appsettings.json + 依赖注入绑定——配置外置(全系列老朋友)。

桌面特有:数据通常本地优先——用户的数据在自己机器上,隐私敏感度更高(第 10 站合规)。

EF Core + SQLite 实战
// ① 实体(类 = 表)
public class Order {
    public int Id { get; set; }
    public string Title { get; set; } = "";
    public decimal Amount { get; set; }
}

// ② DbContext(数据库会话)
public class AppDbContext : DbContext {
    public DbSet<Order> Orders => Set<Order>();
    protected override void OnConfiguring(DbContextOptionsBuilder b)
        => b.UseSqlite("Data Source=ledger.db");   // 单文件数据库!
}

// ③ 增删改查(LINQ 查询,不用拼 SQL)
await using var db = new AppDbContext();
db.Orders.Add(new Order { Title = "办公用品", Amount = 299.00m });
await db.SaveChangesAsync();

var bigOrders = await db.Orders
    .Where(o => o.Amount > 100)
    .OrderByDescending(o => o.Amount)
    .ToListAsync();

// ④ 迁移(表结构版本管理,第16本 Alembic 同款)
// dotnet ef migrations add AddOrderTable
// dotnet ef database update

【配置文件(appsettings.json)】
{
  "ConnectionStrings": { "Default": "Data Source=ledger.db" },
  "Logging": { "LogLevel": { "Default": "Information" } }
}
// 程序里:builder.Configuration.GetConnectionString("Default")

【JSON 序列化(System.Text.Json)】
var json = JsonSerializer.Serialize(orders);     // 对象 → JSON
var back  = JsonSerializer.Deserialize<List<Order>>(json);

【桌面数据要点】
  本地优先:数据存在用户机器(离线可用)
  用户数据目录:%AppData%/你的应用/——标准位置
  大文件/二进制:FileStream 流式读写(别全载内存)

数据层术语

  • EF Core:.NET ORM——LINQ 查数据库,自动迁移。
  • SQLite:单文件数据库——桌面应用标配。
  • System.Text.Json:官方 JSON 序列化。
  • appsettings.json:配置文件——配置外置。
  • 本地优先:数据在用户机器——离线可用、隐私敏感。
  • %AppData%:用户数据标准目录。
  • 迁移(EF Migrations):表结构版本管理——git 式演进。

本站收获:数据层 = EF Core + SQLite(本地数据库)+ JSON/文件(小数据)+ appsettings(配置)。和十六/十四本的 ORM 世界完全同构——桌面端只是「默认本地存储」。

第 7 站

并发异步:UI 线程规则

UI 线程 · Dispatcher · async/await · Task · 死锁

桌面 UI 的铁律:UI 只能由 UI 线程更新(第 1 站消息循环的根源)——后台任务要回 UI 线程才能改界面。async/await 让这件事优雅到「写起来像同步」。

🧙
周师傅

三条铁律:

  • UI 单线程:界面更新必须发生在 UI 线程——别的线程碰控件会崩(第 1 站消息循环的因果)。
  • async/await:异步操作的现代写法——`await` 挂起不阻塞 UI,完成后自动回 UI 线程继续。
  • Task:异步任务的载体——Task.Run 丢后台、Task.WhenAll 等全部(第十六本 Task/线程池的 .NET 版)。

经典坑:死锁——UI 线程等 Task,Task 又等回 UI 线程(.ConfigureAwait(false) 的用武之地);还有「后台改 UI」的跨线程异常。

异步实战:加载数据不卡界面
// ✅ 正确:async/await,UI 不卡
private async void RefreshButton_Click(object sender, RoutedEventArgs e) {
    // await 前:UI 线程(显示加载中)
    statusText.Text = "加载中...";

    var data = await Task.Run(() => service.LoadLargeData());
    // await 后:自动回到 UI 线程!更新界面安全

    ordersList.ItemsSource = data;        // 安全更新 UI
    statusText.Text = $"加载完成:{data.Count} 条";
}

// ❌ 错误:同步阻塞 UI(界面冻结)
private void Bad_Click(object sender, RoutedEventArgs e) {
    var data = service.LoadLargeData();   // UI 冻结!几秒无响应
}

// 并发三件套
var t1 = Task.Run(() => Work1());
var t2 = Task.Run(() => Work2());
await Task.WhenAll(t1, t2);               // 并行等待

// 死锁坑:UI 线程同步等待异步(经典错误)
// var data = service.LoadAsync().Result;   ← 死锁!别这么写
// 正确:全程 await,别用 .Result/.Wait()

【async/await 心法】
  async 方法里遇到 await → 挂起(不占线程)→ 完成后回来
  上下文(UI 线程)自动恢复——这就是「UI 不卡」的秘密
  同步上下文:WPF/WinUI 有 UI 同步上下文,await 自动回主线程

【和第十六本 Python 协程对比】
  Python asyncio:事件循环 + 挂起
  C# async/await:同步上下文 + 挂起
  → 思想一模一样,语法略不同

并发术语

  • UI 线程(消息循环):界面更新的唯一线程——第 1 站的因果。
  • Dispatcher / SynchronizationContext:回 UI 线程的「通道」。
  • async/await:异步一等公民——挂起不阻塞。
  • Task.Run / WhenAll:后台任务 / 并行等待。
  • 死锁:.Result/.Wait() 同步等待异步——UI 经典坑。
  • ConfigureAwait(false):不强制回原上下文——库代码防死锁。
  • 跨线程异常:后台改 UI——崩溃现场。

本站收获:并发 = await 挂起不阻塞 + UI 线程规则(改界面回主线程)+ Task.Run 丢后台。记住:永远别用 .Result 同步等待——async/await 全程到底,UI 永不卡。

第 8 站

工程化:构建与分发

Visual Studio · NuGet · 单元测试 · MSIX 打包 · 自动更新

桌面开发的工程化:IDE 全家桶、测试保障、打包分发、自动更新——「能编译」和「能交付」之间隔着一整套流程。

🧙
周师傅

工程化五件事:

  • Visual Studio:Windows 开发的事实 IDE——调试器、IntelliSense、可视化设计器(XAML 拖拽)。
  • NuGet + 项目引用:包管理 + 模块化(多项目解决方案:App/Core/Data 分层)。
  • 单元测试(xUnit/NUnit):测 ViewModel/业务逻辑——十六/十七本测试老朋友。
  • 打包(MSIX):现代安装包——干净安装卸载、自动更新通道(第 5 站讲过)。
  • 自动更新:桌面软件的「持续交付」——检查更新 → 下载 → 安装 → 重启(App Installer/自建更新服务)。

CI/CD:Azure Pipelines / GitHub Actions——提交代码自动构建、测试、打包(第二本老朋友)。

桌面工程化速览
【解决方案结构(多项目分层)】
Ledger.sln
├── src/
│   ├── Ledger.App/          # WPF/WinUI 主程序(UI 层)
│   ├── Ledger.Core/         # 领域模型(纯逻辑,无 UI 依赖)
│   └── Ledger.Data/         # EF Core 数据层(Repository)
└── tests/
    └── Ledger.Core.Tests/   # 单元测试

【xUnit 测试(十六本 pytest 的 .NET 版)】
[Fact]
public void 金额格式化_千分位正确() {
    var vm = new MainViewModel();
    Assert.Equal("¥1,299.00", vm.FormatAmount(1299.00m));
}

【打包发布(MSIX)】
  Windows 应用打包项目 → 生成 .msix/.msixbundle
  功能:干净安装/卸载、增量更新、证书签名
  → 企业分发:内部服务器 / 应用商店 / Intune

【自动更新方案】
  ① 商店更新(微软商店自动处理)
  ② App Installer(.appinstaller 文件 + Web 托管)
  ③ 自建更新服务(检查版本 → 下载 → 静默安装)

【CI/CD 流水线(GitHub Actions 简版)】
  git push → dotnet test(测试全绿?)
  → dotnet publish(发布构建)
  → 打 MSIX 包 → 签名 → 上传分发渠道
  → 客户端自动更新(第9站讲签名)

工程化术语

  • Visual Studio:Windows 开发 IDE——调试/设计器/IntelliSense。
  • 解决方案(sln):多项目组织——App/Core/Data 分层。
  • xUnit / NUnit:.NET 单元测试框架。
  • MSIX 打包:现代安装包——干净安装/自动更新。
  • 自动更新:App Installer / 自建更新服务——持续交付。
  • CI/CD:Azure Pipelines / GitHub Actions——自动构建测试打包。
  • 发布配置:Debug(调试)/ Release(发布)——签名混淆优化。

本站收获:工程化 = VS 开发 + 多项目分层 + xUnit 测试 + MSIX 打包 + 自动更新 + CI/CD。桌面软件的「交付感」:用户双击安装包,从此自动更新——像商店 App 一样省心。

第 9 站

系统集成:平台能力

P/Invoke · 注册表 · Windows 服务 · 托盘 · 文件关联 · COM

桌面软件和 Web/手机最大的不同:它能「住进系统里」——开机自启、托盘常驻、文件关联、注册表配置。这一站,桌面端的「特权」。

🧙
周师傅

系统集成七件套:

  • P/Invoke:C# 调用 Win32 API——框架没封装的系统能力直接调(第 1 站 API 的现代入口)。
  • 注册表:读写系统配置——软件设置/文件关联/开机启动(操作要小心,权限有边界)。
  • Windows 服务:无界面后台程序——开机自启、常驻运行(监控/同步工具)。
  • 托盘(NotifyIcon):任务栏右下角图标——后台常驻软件的「门面」(QQ/网盘都这样)。
  • 文件关联:双击 .csv 用你的程序打开——注册文件类型关联。
  • 启动项:开机自启(注册表/启动文件夹)——要克制,别惹用户烦。
  • COM 组件:老牌组件模型——调 Office/系统组件(老技术,了解)。
系统集成实战
// ① P/Invoke:C# 调 Win32 API(第1站 API 的现代入口)
[DllImport("user32.dll")]
static extern int MessageBox(IntPtr hWnd, string text,
                             string caption, uint type);

MessageBox(IntPtr.Zero, "你好,Windows!", "Ledger", 0);

// ② 托盘图标:后台常驻
var icon = new NotifyIcon {
    Icon = SystemIcons.Application,
    Text = "轻记账助手",
    Visible = true,
};
icon.ContextMenuStrip = new ContextMenuStrip();
icon.ContextMenuStrip.Items.Add("打开主界面", null, (s, e) => ShowMain());
icon.ContextMenuStrip.Items.Add("退出", null, (s, e) => Exit());

// ③ 文件关联:双击 .ledger 打开
// 注册表注册(HKEY_CLASSES_ROOT\.ledger → 关联你的 exe)

// ④ 开机自启(注册表方式)
// HKCU\Software\Microsoft\Windows\CurrentVersion\Run
// 注意:别偷偷自启!用户知情 + 设置里可关闭

【系统集成注意事项】
  权限边界:注册表 HKCU(当前用户)可写;HKLM(全机)要管理员
  服务 vs 托盘:常驻后台用服务(无 UI);用户可见用托盘
  启动项克制:偷偷自启 = 被卸载的理由(流氓软件画像)
  卸载干净:不留注册表垃圾(MSIX 打包自动处理,第8站)

【桌面特权(对比 Web/手机)】
  Web:没有系统能力(沙箱)
  Android:权限申请制(动态申请)
  Windows 桌面:能力最开放——也最需要自律

系统集成术语

  • P/Invoke:C# 调 Win32 API——系统能力的入口。
  • 注册表:系统配置字典——HKCU 可写、HKLM 要管理员。
  • Windows 服务:无界面常驻程序——开机自启。
  • NotifyIcon(托盘):任务栏图标——后台常驻的门面。
  • 文件关联:双击文件用你的程序打开。
  • 开机自启:启动项——克制使用,别惹人烦。
  • COM:老牌组件模型——调 Office 等(了解)。

本站收获:系统集成 = P/Invoke 调 API + 注册表管配置 + 托盘做常驻 + 文件关联接文件。桌面能力最开放,也最需要自律——「能力越大,越要克制」。

第 10 站

安全质量:桌面规矩

UAC · 代码签名 · SmartScreen · 崩溃监控 · 兼容

桌面软件上线前有一道「鬼门关」:用户下载后被 SmartScreen 拦、杀毒软件报毒、兼容性翻车——这一站,把桌面的规矩讲透。

🧙
周师傅

桌面安全五件事:

  • UAC(用户账户控制):需要管理员权限的操作弹窗确认——程序默认普通权限,别乱要管理员(第 1 站「用户/内核模式」的现代形态)。
  • 代码签名(证书):给 exe/安装包签名——证明「我是正经开发者」;不签名 = SmartScreen 拦 + 杀软误报。
  • SmartScreen / Defender:Windows 的「安全检查」——未签名的新软件会被警告,用户吓跑。
  • 崩溃监控(WER/日志):Windows 错误报告 + 自己的日志——崩溃自动上报(和 Android Crashlytics 同思路)。
  • 版本兼容:Windows 10/11 双版本 + 32/64 位——发布前兼容性测试(第十八本 Android 适配的 Windows 版)。

再加隐私合规:桌面软件收集用户数据同样受个保法约束(第八本老朋友)——收集要告知、可删除。

桌面安全与分发合规
【代码签名流程(软件过审的关键)】
  ① 买代码签名证书(OV/EV 级别,几百到几千元/年)
  ② 用证书给 exe/MSIX 签名(signtool)
  ③ 签名后:SmartScreen 不再「未知发布者」
     → 用户下载安装的信任成本大降
  (没签名 = 下载被警告 = 用户流失!)

【UAC 正确姿势】
  默认普通权限运行(别要求「以管理员运行」)
  真需要管理员的操作(写 HKLM/装驱动)→ 弹 UAC 单独提权
  → 乱要管理员 = 用户警惕 + 安全审计风险

【崩溃监控方案】
  Windows WER(系统级错误上报)+ 自建日志
  崩溃日志:全局异常捕获 → 写本地日志 → 下次启动上传
  → 和 Android Crashlytics 同思路(第十八本老朋友)

【版本兼容清单】
  □ Windows 10 / 11 都测过
  □ 32 位 / 64 位(x86/x64/ARM64)
  □ 高分屏(DPI 缩放)、深色模式
  □ 中文/英文系统(路径/编码 Unicode)

【隐私合规(第八本老朋友)】
  □ 收集数据有隐私政策 + 首次告知
  □ 数据只存本机(本地优先)——别偷偷上传!
  □ 提供「删除我的数据」入口
  → 桌面软件的信任,建立在「不偷数据」上
应用场景:从「未知发布者」到「已信任」

轻记账桌面版第一版没签名——用户下载后 SmartScreen 弹「Windows 已保护你的电脑」,一半用户被吓跑。整改:买 EV 证书 → 签名 → 重新打包 → 用户下载不再警告,安装率提升 3 倍。「代码签名」是桌面软件的第一张信任状。

安全术语

  • UAC:用户账户控制——提权弹窗确认。
  • 代码签名:证书签名 exe/MSIX——SmartScreen 不拦的钥匙。
  • SmartScreen:Windows 安全过滤——未签名软件被警告。
  • WER / 崩溃日志:系统错误上报 + 自建日志——崩溃可追踪。
  • 版本兼容:Win10/11、32/64 位、高分屏——发布前必测。
  • 隐私合规:个保法——本地优先 + 不偷传数据。
  • 信任状:签名证书 = 桌面软件的「身份证」。

本站收获:安全 = 代码签名保信任 + UAC 克制提权 + 崩溃监控盯质量 + 兼容性测试保覆盖 + 隐私合规守底线。桌面软件的规矩,第一条就是「让用户敢装」。

附录

知识点速查 + 面试高频题

面试/交付前最后一页

Windows 开发知识全景表

领域核心知识点一句话人话
平台架构Win32 API、消息循环、句柄、用户/内核模式系统怎么组织
技术栈Win32→MFC→WPF→UWP→WinUI 3→MAUI/Qt/Electron40 年选型地图
C#/.NETCLR、LINQ、async/await、NuGet、DI现代主力语言
WPFXAML、数据绑定、MVVM、Dispatcher桌面 UI 经典王者
WinUI 3Fluent、Windows App SDK、MSIX新方向
数据层EF Core、SQLite、JSON、appsettings本地优先存储
并发异步UI 线程、async/await、Task、死锁UI 永不卡
工程化VS、xUnit、MSIX、自动更新、CI/CD从源码到安装包
系统集成P/Invoke、注册表、托盘、文件关联、服务住进系统里
安全质量UAC、代码签名、SmartScreen、崩溃监控、兼容让用户敢装

面试高频题速记

  • Windows 程序的消息循环是什么?→ 事件驱动泵——窗口消息取→派发→处理,UI 单线程的根源。
  • WPF 和 WinUI 3 区别?→ 经典成熟 vs 现代 Fluent——XAML 语法同源,新项目选 WinUI 3。
  • 为什么 UI 只能在主线程更新?→ 消息循环 + 线程安全——后台改 UI 会崩,用 Dispatcher/await。
  • async/await 怎么做到 UI 不卡?→ await 挂起不占线程,完成后自动回 UI 同步上下文。
  • C# 的 LINQ 是什么?→ 集合查询语法——Where/Select/OrderBy 链式(Java Stream 亲戚)。
  • 什么是死锁?→ .Result/.Wait() 同步等异步 + UI 上下文——永远全程 await。
  • 为什么代码要签名?→ SmartScreen 信任 + 防篡改——不签名用户不敢装。
  • WPF 的 MVVM 是什么?→ ViewModel + 数据绑定——界面逻辑分离(Android 同款)。
  • 桌面数据存哪?→ SQLite(单文件数据库)+ %AppData%——本地优先。
  • UAC 是什么?→ 用户账户控制——提权弹窗,程序默认普通权限。
系统 消息循环
选型 技术栈地图
语言 C#/.NET
UI WPF/WinUI
数据 EF/SQLite
异步 async/await
工程 打包更新
安全 签名合规 🚀
Windows 开发 = 懂系统 + 选对栈 + C# 打底 + 会打包签名——
一半是技术,一半是「规矩」。
消息循环是心脏,XAML 是语言,MVVM 是组织,签名是信任——
四十年的技术栈层层叠叠,但底层的道理从未变过:
桌面开发的本质,是「住进用户的电脑里,还让他放心」。
🪟 🧱 🗺️ 💠 🖥️ ✨ 🗄️ 🔀 📦 🛡️ 🚀 🌳
✌ 语言