Skip to content

feat: 加入用户环境依赖检查#2605

Open
tangge233 wants to merge 4 commits intodevfrom
feat/dep-check
Open

feat: 加入用户环境依赖检查#2605
tangge233 wants to merge 4 commits intodevfrom
feat/dep-check

Conversation

@tangge233
Copy link
Contributor

@tangge233 tangge233 commented Mar 15, 2026

Close #387

Summary by Sourcery

添加一个启动依赖检查服务,用于验证所需的 Windows 运行时组件是否已安装,并通过 Microsoft Store 提示引导用户安装缺失的包。

新功能:

  • 引入环境依赖检查,在应用启动时运行,检查用于图形和图像支持所需的特定 Windows 软件包是否存在。
  • 当未检测到所需组件时,提示用户从 Microsoft Store 安装缺失的依赖项。
Original summary in English

Summary by Sourcery

Add a startup dependency check service that verifies required Windows runtime components are installed and guides users to install missing packages via Microsoft Store prompts.

New Features:

  • Introduce an environment dependency check that runs on app startup and inspects the presence of specific Windows packages needed for graphics and image support.
  • Prompt users to install missing dependencies from Microsoft Store when required components are not detected.

@pcl-ce-automation pcl-ce-automation bot added 🛠️ 等待审查 Pull Request 已完善,等待维护者或负责人进行代码审查 size: L PR 大小评估:大型 labels Mar 15, 2026
Copy link
Member

@LinQingYuu LinQingYuu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

请把它丢到 PCL.Core.App,而不是新开一个命名空间

LinQingYuu
LinQingYuu previously approved these changes Mar 15, 2026
Big-Cake-jpg
Big-Cake-jpg previously approved these changes Mar 15, 2026
Copy link
Member

@Big-Cake-jpg Big-Cake-jpg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

大概看了眼应该没啥问题。

LinQingYuu
LinQingYuu previously approved these changes Mar 16, 2026
@tangge233
Copy link
Contributor Author

@sourcery-ai review

@sourcery-ai
Copy link

sourcery-ai bot commented Mar 16, 2026

审阅者指南

引入了一个新的 DependencyCheckService,它会在应用程序启动时运行,通过 PowerShell 检查所需的 Microsoft Store 包(OpenGL 兼容包和 WebP 扩展),如果缺失则提示用户安装。

应用程序启动时依赖检查的时序图

sequenceDiagram
    participant AppLifecycle
    participant DependencyCheckService
    participant RuntimeInformation
    participant PowerShell
    participant MsgBoxWrapper
    actor User
    participant MsStore

    AppLifecycle->>DependencyCheckService: _Start()
    DependencyCheckService->>RuntimeInformation: OSArchitecture
    alt OSArchitecture is Arm64
        DependencyCheckService->>DependencyCheckService: _CheckAndAsk(Microsoft.D3DMappingLayers, OpenGL兼容包, 9nqpsl29bfff)
        DependencyCheckService->>DependencyCheckService: _CheckPakcageAsync(Microsoft.D3DMappingLayers)
        DependencyCheckService->>PowerShell: Start powershell.exe Get-AppxPackage
        PowerShell-->>DependencyCheckService: JSON package list
        alt package not found
            DependencyCheckService->>MsgBoxWrapper: Show(缺失OpenGL兼容包)
            MsgBoxWrapper-->>User: 显示对话框
            User-->>MsgBoxWrapper: 选择确定
            MsgBoxWrapper-->>DependencyCheckService: selection = 1
            DependencyCheckService->>DependencyCheckService: _LaunchMsStore(9nqpsl29bfff)
            DependencyCheckService->>MsStore: ms-windows-store://pdp?...productid=9nqpsl29bfff
        else package found
            DependencyCheckService-->>AppLifecycle: 继续启动
        end
    end
    DependencyCheckService->>DependencyCheckService: _CheckAndAsk(Microsoft.WebpImageExtension, WebP组件包, 9pg2dk419drg)
    DependencyCheckService->>DependencyCheckService: _CheckPakcageAsync(Microsoft.WebpImageExtension)
    DependencyCheckService->>PowerShell: Start powershell.exe Get-AppxPackage
    PowerShell-->>DependencyCheckService: JSON package list
    alt WebP组件包缺失
        DependencyCheckService->>MsgBoxWrapper: Show(缺失WebP组件包)
        MsgBoxWrapper-->>User: 显示对话框
        User-->>MsgBoxWrapper: 选择确定或稍后
        MsgBoxWrapper-->>DependencyCheckService: selection
        alt selection == 确定
            DependencyCheckService->>DependencyCheckService: _LaunchMsStore(9pg2dk419drg)
            DependencyCheckService->>MsStore: ms-windows-store://pdp?...productid=9pg2dk419drg
        else selection == 稍后
            DependencyCheckService-->>AppLifecycle: 不打开商店
        end
    else WebP组件包已安装
        DependencyCheckService-->>AppLifecycle: 继续启动
    end
Loading

新增 DependencyCheckService 的类图

classDiagram
    class DependencyCheckService {
        <<sealed>>
        +_Start() Task
        +_CheckAndAsk(packageId string, packageName string, storeId string) Task
        +_LaunchMsStore(id string) void
        +_CheckPakcageAsync(id string) Task~bool~
        +CheckPackSuit(jnode JsonNode, id string) bool
    }

    class MsgBoxWrapper {
        +Show(message string, buttons string[]) int
    }

    class ProcessStartInfo {
        +FileName string
        +Arguments string
        +UseShellExecute bool
        +RedirectStandardOutput bool
        +RedirectStandardError bool
        +CreateNoWindow bool
    }

    class Process {
        +StartInfo ProcessStartInfo
        +Start() bool
    }

    class RuntimeInformation {
        +OSArchitecture Architecture
    }

    class Context {
        +Info(message string) void
    }

    DependencyCheckService ..> MsgBoxWrapper : uses
    DependencyCheckService ..> ProcessStartInfo : creates
    DependencyCheckService ..> Process : creates
    DependencyCheckService ..> RuntimeInformation : reads
    DependencyCheckService ..> Context : logs
Loading

文件级变更

变更 详情 文件
添加启动时依赖检查服务,用于验证所需 Microsoft Store 包是否存在,并在需要时打开商店进行安装。
  • 创建带有生命周期属性的 DependencyCheckService,使其在应用程序启动时自动运行
  • 在 ARM64 系统上,检查 Microsoft.D3DMappingLayers OpenGL 兼容包,并始终检查 Microsoft.WebpImageExtension
  • 如果依赖缺失,显示消息框提示用户打开 Microsoft Store 安装该包,并在确认后使用自定义 URI 启动商店
  • 实现基于 PowerShell 的包检测流程,运行 Get-AppxPackage,使用 System.Text.Json.Nodes 解析 JSON,并检查包的 Name 字段以确定目标包是否已安装
PCL.Core/App/Tools/DependencyCheckService.cs

与关联 issue 的对照评估

Issue 目标 是否解决 说明
#387 在 ARM64 系统上检测是否已安装 Microsoft OpenGL 兼容包(OpenGL compatibility pack),若缺失则通知用户并提供打开 Microsoft Store 安装页面的选项。
#387 在执行 OpenGL 兼容包检查前,添加逻辑专门检测设备是否使用 Qualcomm 处理器。 新的 DependencyCheckService 仅检查 RuntimeInformation.OSArchitecture 是否为 Architecture.Arm64;不会检查 CPU 厂商/型号,因此不存在 Qualcomm 专用检测。

提示与命令

与 Sourcery 交互

  • 触发新审阅: 在 pull request 中评论 @sourcery-ai review
  • 继续讨论: 直接回复 Sourcery 的审阅评论。
  • 从审阅评论生成 GitHub issue: 通过回复审阅评论让 Sourcery 从中创建 issue。你也可以在审阅评论中回复 @sourcery-ai issue 来从该评论创建 issue。
  • 生成 pull request 标题: 在 pull request 标题的任意位置写入 @sourcery-ai,即可随时生成标题。你也可以在 pull request 中评论 @sourcery-ai title 来(重新)生成标题。
  • 生成 pull request 摘要: 在 pull request 正文任意位置写入 @sourcery-ai summary,即可在指定位置生成 PR 摘要。你也可以在 pull request 中评论 @sourcery-ai summary 来(重新)生成摘要。
  • 生成审阅者指南: 在 pull request 中评论 @sourcery-ai guide,即可随时(重新)生成审阅者指南。
  • 解决所有 Sourcery 评论: 在 pull request 中评论 @sourcery-ai resolve,即可解决所有 Sourcery 评论。如果你已经处理了所有评论并且不想再看到它们,会很有用。
  • 忽略所有 Sourcery 审阅: 在 pull request 中评论 @sourcery-ai dismiss,即可忽略所有现有的 Sourcery 审阅。尤其适用于你想从一个全新的审阅开始——别忘了再评论 @sourcery-ai review 来触发新审阅!

自定义你的体验

访问你的 控制台 以:

  • 启用或禁用审阅功能,例如 Sourcery 生成的 pull request 摘要、审阅者指南等。
  • 更改审阅语言。
  • 添加、移除或编辑自定义审阅指令。
  • 调整其他审阅设置。

获取帮助

Original review guide in English

Reviewer's Guide

Introduces a new DependencyCheckService that runs at application startup to check for required Microsoft Store packages (OpenGL compatibility and WebP extension) via PowerShell and prompts the user to install them if missing.

Sequence diagram for dependency check at application startup

sequenceDiagram
    participant AppLifecycle
    participant DependencyCheckService
    participant RuntimeInformation
    participant PowerShell
    participant MsgBoxWrapper
    actor User
    participant MsStore

    AppLifecycle->>DependencyCheckService: _Start()
    DependencyCheckService->>RuntimeInformation: OSArchitecture
    alt OSArchitecture is Arm64
        DependencyCheckService->>DependencyCheckService: _CheckAndAsk(Microsoft.D3DMappingLayers, OpenGL兼容包, 9nqpsl29bfff)
        DependencyCheckService->>DependencyCheckService: _CheckPakcageAsync(Microsoft.D3DMappingLayers)
        DependencyCheckService->>PowerShell: Start powershell.exe Get-AppxPackage
        PowerShell-->>DependencyCheckService: JSON package list
        alt package not found
            DependencyCheckService->>MsgBoxWrapper: Show(缺失OpenGL兼容包)
            MsgBoxWrapper-->>User: 显示对话框
            User-->>MsgBoxWrapper: 选择确定
            MsgBoxWrapper-->>DependencyCheckService: selection = 1
            DependencyCheckService->>DependencyCheckService: _LaunchMsStore(9nqpsl29bfff)
            DependencyCheckService->>MsStore: ms-windows-store://pdp?...productid=9nqpsl29bfff
        else package found
            DependencyCheckService-->>AppLifecycle: 继续启动
        end
    end
    DependencyCheckService->>DependencyCheckService: _CheckAndAsk(Microsoft.WebpImageExtension, WebP组件包, 9pg2dk419drg)
    DependencyCheckService->>DependencyCheckService: _CheckPakcageAsync(Microsoft.WebpImageExtension)
    DependencyCheckService->>PowerShell: Start powershell.exe Get-AppxPackage
    PowerShell-->>DependencyCheckService: JSON package list
    alt WebP组件包缺失
        DependencyCheckService->>MsgBoxWrapper: Show(缺失WebP组件包)
        MsgBoxWrapper-->>User: 显示对话框
        User-->>MsgBoxWrapper: 选择确定或稍后
        MsgBoxWrapper-->>DependencyCheckService: selection
        alt selection == 确定
            DependencyCheckService->>DependencyCheckService: _LaunchMsStore(9pg2dk419drg)
            DependencyCheckService->>MsStore: ms-windows-store://pdp?...productid=9pg2dk419drg
        else selection == 稍后
            DependencyCheckService-->>AppLifecycle: 不打开商店
        end
    else WebP组件包已安装
        DependencyCheckService-->>AppLifecycle: 继续启动
    end
Loading

Class diagram for the new DependencyCheckService

classDiagram
    class DependencyCheckService {
        <<sealed>>
        +_Start() Task
        +_CheckAndAsk(packageId string, packageName string, storeId string) Task
        +_LaunchMsStore(id string) void
        +_CheckPakcageAsync(id string) Task~bool~
        +CheckPackSuit(jnode JsonNode, id string) bool
    }

    class MsgBoxWrapper {
        +Show(message string, buttons string[]) int
    }

    class ProcessStartInfo {
        +FileName string
        +Arguments string
        +UseShellExecute bool
        +RedirectStandardOutput bool
        +RedirectStandardError bool
        +CreateNoWindow bool
    }

    class Process {
        +StartInfo ProcessStartInfo
        +Start() bool
    }

    class RuntimeInformation {
        +OSArchitecture Architecture
    }

    class Context {
        +Info(message string) void
    }

    DependencyCheckService ..> MsgBoxWrapper : uses
    DependencyCheckService ..> ProcessStartInfo : creates
    DependencyCheckService ..> Process : creates
    DependencyCheckService ..> RuntimeInformation : reads
    DependencyCheckService ..> Context : logs
Loading

File-Level Changes

Change Details Files
Add startup dependency check service that validates presence of required Microsoft Store packages and optionally opens the Store for installation.
  • Create DependencyCheckService with lifecycle attributes so it runs automatically at application startup
  • On ARM64 systems, check for the Microsoft.D3DMappingLayers OpenGL compatibility package and always check for Microsoft.WebpImageExtension
  • If a dependency is missing, show a message box prompting the user to open Microsoft Store to install the package, and launch the Store using a custom URI when confirmed
  • Implement a PowerShell-based package detection routine that runs Get-AppxPackage, parses the JSON with System.Text.Json.Nodes, and inspects package Name fields to determine if the target package is installed
PCL.Core/App/Tools/DependencyCheckService.cs

Assessment against linked issues

Issue Objective Addressed Explanation
#387 On ARM64 systems, detect whether the Microsoft OpenGL 兼容包 (OpenGL compatibility pack) is installed, and if missing, notify the user and offer to open the Microsoft Store install page.
#387 Add logic that specifically detects whether the device uses a Qualcomm processor before performing the OpenGL compatibility pack check. The new DependencyCheckService only checks RuntimeInformation.OSArchitecture for Architecture.Arm64; it does not inspect CPU vendor/model, so there is no Qualcomm-specific detection.

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - 我发现了两个问题,并给了一些总体反馈:

  • _CheckPakcageAsync 方法中,foreach 循环使用 foreach (var node in jnode.AsArray()) 进行迭代,但仍然将 jnode 传入 CheckPackSuit;这里很可能应该传入 node,这样才能实际检查数组中的每个元素。
  • 方法名 _CheckPakcageAsync 有拼写错误,应重命名为 _CheckPackageAsync(并更新所有调用处),以保持命名一致并避免混淆。
  • 由于这段代码会调用 powershell.exe,建议对 _CheckPakcageAsync_Start 增加仅限 Windows 的系统检查(例如 RuntimeInformation.IsOSPlatform(OSPlatform.Windows)),以避免在非 Windows 平台上出现错误。
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In the `_CheckPakcageAsync` method, the `foreach` loop iterates `foreach (var node in jnode.AsArray())` but still passes `jnode` into `CheckPackSuit`; this should likely pass `node` so each entry is actually inspected.
- The method name `_CheckPakcageAsync` contains a typo and should be renamed to `_CheckPackageAsync` (and all call sites updated) to keep naming consistent and avoid confusion.
- Since this code shells out to `powershell.exe`, consider guarding `_CheckPakcageAsync` and `_Start` with a Windows-only OS check (e.g., `RuntimeInformation.IsOSPlatform(OSPlatform.Windows)`) to avoid failures on non-Windows platforms.

## Individual Comments

### Comment 1
<location path="PCL.Core/App/Tools/DependencyCheckService.cs" line_range="85-87" />
<code_context>
+        if (jnode.GetValueKind().Equals(JsonValueKind.Array))
+        {
+            var hasPack = false;
+            foreach (var node in jnode.AsArray())
+            {
+                if (CheckPackSuit(jnode, id))
+                {
+                    hasPack = true;
</code_context>
<issue_to_address>
**issue (bug_risk):** Array iteration likely checks the wrong JsonNode instance, leading to incorrect detection.

Inside the `foreach (var node in jnode.AsArray())` loop, `CheckPackSuit` is called with `jnode` instead of `node`, so the same array node is checked on every iteration instead of each element. This will produce the same result for every pass and likely never detect the intended match. Use `CheckPackSuit(node, id)` to evaluate each array item correctly.
</issue_to_address>

### Comment 2
<location path="PCL.Core/App/Tools/DependencyCheckService.cs" line_range="53" />
<code_context>
+        ps.Start();
+    }
+
+    private static async Task<bool> _CheckPakcageAsync(string id)
+    {
+        var command = $"Get-AppxPackage -Name *{id}* | ConvertTo-Json";
</code_context>
<issue_to_address>
**nitpick (typo):** Method name contains a typo that could hurt readability and discoverability.

`_CheckPakcageAsync` seems to misspell `Package`. Please rename it to `_CheckPackageAsync` for consistency and easier searchability.

Suggested implementation:

```csharp
    private static async Task<bool> _CheckPackageAsync(string id)

```

Search the entire solution for `_CheckPakcageAsync` and update all call sites to `_CheckPackageAsync` to keep the code compiling and consistent.
</issue_to_address>

Sourcery 对开源项目是免费的——如果你觉得这些代码审查有帮助,欢迎分享 ✨
帮我变得更有用!请对每条评论点选 👍 或 👎,我会根据你的反馈改进后续的代码审查。
Original comment in English

Hey - I've found 2 issues, and left some high level feedback:

  • In the _CheckPakcageAsync method, the foreach loop iterates foreach (var node in jnode.AsArray()) but still passes jnode into CheckPackSuit; this should likely pass node so each entry is actually inspected.
  • The method name _CheckPakcageAsync contains a typo and should be renamed to _CheckPackageAsync (and all call sites updated) to keep naming consistent and avoid confusion.
  • Since this code shells out to powershell.exe, consider guarding _CheckPakcageAsync and _Start with a Windows-only OS check (e.g., RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) to avoid failures on non-Windows platforms.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In the `_CheckPakcageAsync` method, the `foreach` loop iterates `foreach (var node in jnode.AsArray())` but still passes `jnode` into `CheckPackSuit`; this should likely pass `node` so each entry is actually inspected.
- The method name `_CheckPakcageAsync` contains a typo and should be renamed to `_CheckPackageAsync` (and all call sites updated) to keep naming consistent and avoid confusion.
- Since this code shells out to `powershell.exe`, consider guarding `_CheckPakcageAsync` and `_Start` with a Windows-only OS check (e.g., `RuntimeInformation.IsOSPlatform(OSPlatform.Windows)`) to avoid failures on non-Windows platforms.

## Individual Comments

### Comment 1
<location path="PCL.Core/App/Tools/DependencyCheckService.cs" line_range="85-87" />
<code_context>
+        if (jnode.GetValueKind().Equals(JsonValueKind.Array))
+        {
+            var hasPack = false;
+            foreach (var node in jnode.AsArray())
+            {
+                if (CheckPackSuit(jnode, id))
+                {
+                    hasPack = true;
</code_context>
<issue_to_address>
**issue (bug_risk):** Array iteration likely checks the wrong JsonNode instance, leading to incorrect detection.

Inside the `foreach (var node in jnode.AsArray())` loop, `CheckPackSuit` is called with `jnode` instead of `node`, so the same array node is checked on every iteration instead of each element. This will produce the same result for every pass and likely never detect the intended match. Use `CheckPackSuit(node, id)` to evaluate each array item correctly.
</issue_to_address>

### Comment 2
<location path="PCL.Core/App/Tools/DependencyCheckService.cs" line_range="53" />
<code_context>
+        ps.Start();
+    }
+
+    private static async Task<bool> _CheckPakcageAsync(string id)
+    {
+        var command = $"Get-AppxPackage -Name *{id}* | ConvertTo-Json";
</code_context>
<issue_to_address>
**nitpick (typo):** Method name contains a typo that could hurt readability and discoverability.

`_CheckPakcageAsync` seems to misspell `Package`. Please rename it to `_CheckPackageAsync` for consistency and easier searchability.

Suggested implementation:

```csharp
    private static async Task<bool> _CheckPackageAsync(string id)

```

Search the entire solution for `_CheckPakcageAsync` and update all call sites to `_CheckPackageAsync` to keep the code compiling and consistent.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size: L PR 大小评估:大型 🛠️ 等待审查 Pull Request 已完善,等待维护者或负责人进行代码审查

Projects

None yet

Development

Successfully merging this pull request may close these issues.

在 ARM64 版 PCL-CE 中添加对高通处理器并且是否安装“OpenGL兼容包”的检测

4 participants