docs(m196): r2 复审 —— 给「无控制台宿主」那条下边界声明
复审指出 README §15 把两个**近似**形态(父进程句柄不继承 / 父子都无句柄)直接叫「服务形状」, 顶层又写「服务 / 计划任务」,读者会把它当成「真服务也测过」。补一段边界:① ② 都是近似, 真 SCM 服务与计划任务(session 0、no window station)、start /b、ConPTY 全部未测,结论靠 「句柄无效时 std 写返回 Ok」这条机制外推;第三方交叉读数(复审 r2 那组)单独标注来源, 不混进我自己的读数。 同一处过度概括也出现在 console.rs 的 NoConsole 文档(原文「④ / 服务 / 计划任务」), 按同一口径改成「④ 双击,以及其他没有控制台的宿主」并指向 README §15 的边界段。 只改文档,不动代码。
This commit is contained in:
1 parent
3fd33a672f
commit
26ba1579ab
2 files changed
+19
-12
No files matched your search
@@ -104,7 +104,8 @@ pub enum ConsoleOutcome {
|
||||
/// 附着后 `(stdout, stderr)`。
|
||||
after: (isize, isize),
|
||||
},
|
||||
/// 没有可写的控制台(④ / 服务 / 计划任务):附着失败**或**附着成功但句柄仍不可用。
|
||||
/// 没有可写的控制台(④ 双击,以及其他没有控制台的宿主):附着失败**或**附着成功但
|
||||
/// 句柄仍不可用。服务 / 计划任务只是**近似**形态、未亲测,边界见 `packaging/README.md` §15。
|
||||
///
|
||||
/// 两种情况在调用点上是同一件事(都没有输出通道),所以合并成一个结论;`last_error` 与
|
||||
/// 两对句柄一起进诊断文本,读的人能自己分清是哪一种。**没有新建任何窗口**。
|
||||
|
||||
+17
-11
@@ -166,14 +166,20 @@ CUI(3),`grep -rn windows_subsystem crates/` 当时零命中。同一个修复
|
||||
`.github/workflows/ci.yml` 的 `build` job(PR 阶段就红,不必等到 tag)。
|
||||
- 抓不住(如实记):只看那 4 个字节,不看 GUI 双击的实际观感——「不再多一个黑框」在本仓库的验证环境
|
||||
(RDP / 无干净无控制台桌面)只能由 PE 头 + 进程/窗口枚举间接证明,人眼验收归真机。
|
||||
- **既无控制台也不重定向的宿主(快捷方式 / 服务 / 计划任务):输出照旧无处可去,退出码不变**
|
||||
(M196 r2 实测,覆盖 r1 复审 P2-3 提出的「退出码会变成 `EXIT_INTERNAL`(2)」——那条实测不成立)。
|
||||
两种宿主形态各测两条命令,`child_exit_code` 全是 **0**:①父进程有 std 句柄但子进程不继承;
|
||||
②父子都没有 std 句柄(服务形状,子进程实测 `stdin/stdout/stderr = 0x0`、`AttachConsole` 返回 0 /
|
||||
`GetLastError=6`)。原因在 Rust std 的 Windows 实现:句柄取不到时 `Write`/`flush` 直接返回 `Ok`
|
||||
(独立探针实测 `SetStdHandle(out)` = `0x0` / `0x1234` / `(HANDLE)-1` 三种取值,`write=Ok(())`、
|
||||
`flush=Ok(())` 全成立),所以 `crates/cli/src/runner.rs` 那条「写失败 ⇒ `EXIT_INTERNAL`」的分支不会
|
||||
被触发。结论:本 diff **没有**给 CLI 退出码引入可观察差异;真正的差异只有「没控制台就没人看得见输出」
|
||||
这件事,而 CUI 时代在服务里同样是隐形的。想让这种情形有专属退出码/文案,得在 CLI 侧显式判一次能力
|
||||
(`platform::win32::console` 的 `output_visible()` 就是现成的判据),那在 `crates/cli/**`、不在 M196 的
|
||||
scope 内——这里只如实记录形态,不改结构。
|
||||
- **既无控制台也不重定向的宿主:输出照旧无处可去,退出码不变**(M196 r2 实测,反驳 r1 复审 P2-3 的
|
||||
「退出码会变成 `EXIT_INTERNAL`(2)」——那条是**纯推理、无实测**)。两个**近似**形态 × 两条命令,
|
||||
`child_exit_code` 全是 **0**:① 父进程有 std 句柄、子进程不继承(`dwFlags=0` + `bInheritHandles=FALSE`);
|
||||
② 父进程 `FreeConsole()` 后把 `in/out/err` 三个 std 句柄全置 0,再起子进程(子进程侧实测
|
||||
`stdin/stdout/stderr = 0x0`、`AttachConsole` 返回 0 / `GetLastError=6`)。原因在 Rust std 的 Windows
|
||||
实现:句柄取不到时 `Write`/`flush` 直接返回 `Ok`(独立探针实测 `SetStdHandle(out)` = `0x0` / `0x1234` /
|
||||
`(HANDLE)-1` 三种取值,`write=Ok(())`、`flush=Ok(())` 全成立),所以 `crates/cli/src/runner.rs` 那条
|
||||
「写失败 ⇒ `EXIT_INTERNAL`」的分支不会被触发。结论:本 diff **没有**给 CLI 退出码引入可观察差异;
|
||||
真正的差异只有「没控制台就没人看得见输出」这件事本身。
|
||||
**边界(别把上面读成「真服务也测过」)**:①② 都只是**近似**形态——真 SCM 服务与计划任务(session 0、
|
||||
no window station)、`start /b`、Windows Terminal / ConPTY 全部**未测**;对它们的结论只能靠「句柄无效
|
||||
时 std 写返回 `Ok`」这条机制外推,不是在那些形态里亲测。第三方交叉(**复审的读数,不是我跑的**):
|
||||
r1 复审在 r2 用更干净的形态(父 `FreeConsole()` + 三句柄置 0 + 子进程
|
||||
`DETACHED_PROCESS | dwFlags=0 | bInheritHandles=FALSE`)独立复现,产品二进制 `--version` /
|
||||
`instances list` / `--help` 全 0(`logs list` 是 1,但重定向跑同一条也是 1 ⇒ 用户错误,不是写失败)。
|
||||
想让这种情形有专属退出码/文案,得在 CLI 侧显式判一次能力(`platform::win32::console` 的
|
||||
`output_visible()` 就是现成判据),那在 `crates/cli/**`、不在 M196 的 scope 内——这里只如实记录形态。
|
||||
Reference in new issue
Block a user