Files
chuan 5ce2c8a982 feat: Claude Code 原生 Windows 通知(C# / .NET 10 + Avalonia 12)
为 Claude Code 提供原生 Windows toast 通知:点击跳回原窗口、切回 Windows
Terminal 标签、跨虚拟桌面、调用方图标、非阻塞投递;NativeAOT 单文件分发。
2026-06-22 18:05:15 +08:00

40 lines
2.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 原生互操作与 AOT
所有 Win32 / COM 互操作都为 **NativeAOT** 准备:用 `LibraryImport`(源生成 P/Invoke)和 `[GeneratedComInterface]`(源生成 COM),**不用** `System.Drawing`、经典 `[ComImport]`、反射式封送(它们在 AOT 下不可用)。
| 文件 | 职责 | 关键点 |
|------|------|--------|
| `Win32.cs` | 基础 P/Invoke | `GetForegroundWindow``GetClassName`、工具窗口样式等 |
| `WindowActivator.cs` | 抢前台激活 | ALT 模拟 + `AttachThreadInput` + 多 API 组合,绕过防焦点抢占 |
| `WinTerminalTabs.cs` | WT 切标签 | 源生成 COM 调 UIAutomation,按 RuntimeId 定位标签 |
| `VirtualDesktopPinner.cs` | 跨虚拟桌面 | 未公开 COM `IVirtualDesktopPinnedApps.PinView` |
| `ProcessTree.cs` | 进程树上溯 | Toolhelp 快照,跳过 shell/运行时找调用方 App |
| `AppIcon.cs` | 取图标 | `ExtractIconEx` + GDI 读 BGRA 像素 → Avalonia 位图 |
| `Sound.cs` | 提示音 | winmm `PlaySound` 从内存异步播放 |
## 窗口激活(WindowActivator
Windows 限制后台进程抢焦点。组合技:还原最小化 → 模拟一次 ALT 抬起 → `AttachThreadInput` 把当前线程与前台/目标线程输入队列挂接 → `AllowSetForegroundWindow` + `SetWindowPos`/`BringWindowToTop`/`SwitchToThisWindow`/`SetForegroundWindow` 多管齐下 → 解除挂接。
## Windows Terminal 切标签(WinTerminalTabs
- `save` 时:检测前台窗口类是否 `CASCADIA_HOSTING_WINDOW_CLASS`;是则用 UIAutomation 找当前选中的 `TabItem`,取其 **RuntimeId**(一串 intSAFEARRAY)存入状态。
- 点击时:激活 WT 窗口后,枚举标签找到 RuntimeId 匹配的,调 `SelectionItemPattern.Select()`
- **AOT 要点**:接口用 `[GeneratedComInterface]`;未用到的 vtable 槽用占位方法按 SDK 头文件顺序补齐(顺序 / GUID 均取自 `UIAutomationClient.h`);`IApplicationView` 以裸 `IntPtr` 传递。
## 跨虚拟桌面(VirtualDesktopPinner
-`CoCreateInstance``CLSCTX_LOCAL_SERVER`)拿 ImmersiveShell → `IApplicationViewCollection.GetViewForHwnd``IVirtualDesktopPinnedApps.PinView`
- GUID 取自 Win11 24H2;整段 try/catch,失败自动退回"仅当前桌面"。
- 窗口刚打开时 view 可能尚未就绪,短间隔重试直到成功。
## 取图标(AppIcon
`ExtractIconEx` 拿 HICON → `GetIconInfo` 取彩色位图 → `GetDIBits` 以 32bpp 自上而下读出 BGRA → 构造 `Avalonia.Media.Imaging.Bitmap`。老图标无 alpha(全 0)时补成不透明,避免整块透明。取不到则回退默认 Claude 图标。
## AOT
- `csproj``IsAotCompatible``PublishAot` 条件块 + `TrimmerRootAssembly`Ursa / Semi 整体保留)+ `CoreUtils.*.Static` 静态链接 Skia / HarfBuzz / ANGLE。
- 原生链接需要 MSVC 工具链(从 "Developer Command Prompt for VS" 跑,或用配好 vcvars 的脚本)。
- 源生成 COM / UIAutomation 与静态渲染需在真机运行验证。