fix(app-iced): M100 r1b —— 把 unsafe 收回唯一标记文件(IsWindow 搬回 transparency.rs)

复审实测抓到:`transparency/exstyle.rs` 里写了 `extern "system" { fn IsWindow }` 与
`unsafe { IsWindow(hwnd) }`,而该文件**没有** `#![allow(unsafe_code)]`。它编得过是因为 lint
级别沿模块树继承;`guards.yml` 的 unsafe-scope 判的是「**带放行属性**的文件集合恰好等于
transparency.rs」⇒ 门禁照样绿,但「全仓唯一允许 unsafe 的文件」这个**性质**已经破了。
这正是「门禁通过 ≠ 性质成立」。

做法(与既有 `raw_ex_style` 同款,不加新面):
- `transparency.rs` 的 `extern "system"` 块里补 `IsWindow` 声明,并新增安全包装
  `pub(super) fn window_exists(hwnd) -> bool`(0 / 无效句柄 → false)。
- `exstyle.rs` 改成 `if hwnd == 0 || !super::window_exists(hwnd) { return None }`,
  自身**零 unsafe、零 extern**;文档里也不再出现 `unsafe {` 字面量,好让「全仓 unsafe 块
  位置集合 ⊆ {transparency.rs}」这句话能直接用 grep 复核。
- 行数:transparency.rs 385 / exstyle.rs 107(都 <400);测试仍 399 条,无增删。

三态行为不变(重跑对照):默认 `passthrough_ext=on` ×5、`--passthrough=off` 为 `off` ×3;
两者 sha256 都是 `0d7b4f5b…`(再次印证 hash 对密闭零判别力);真控件图仍 `414a71fc…`。
This commit is contained in:
AskaEth committed 2026-11-03 15:48:09 +08:00
1 parent 380fac0324
commit 839a142db0
2 files changed
+41 -20

No files matched your search

@@ -191,6 +191,20 @@ fn has_layered(hwnd: isize) -> bool {
raw_ex_style(hwnd) & WS_EX_LAYERED != 0
}
/// 句柄是否指向一个**存在**的窗口(全仓唯一 `unsafe` 落点的一部分)。
///
/// 为什么在这里而不是在取证探针那个文件里:`transparency.rs` 是全仓**唯一**允许 `unsafe` 的
/// 文件(`unsafe-scope` 判据 = 「带 `#![allow(unsafe_code)]` 的文件集合恰好等于本文件」)。
/// 探针用到 FFI 时就只能**把 FFI 搬进来**,不能让 `unsafe` 溜到没有标记的文件里——
/// 那会让门禁照样绿、而「唯一落点」这个性质已经破了(M100 r1 复审实测抓到的形状)。
///
/// `0` / 无效句柄 → `false`(Win32 的 `IsWindow` 对无效句柄返回 0)。
#[cfg(target_os = "windows")]
pub(super) fn window_exists(hwnd: isize) -> bool {
// SAFETY: `IsWindow` 只按值接受句柄,不持有指针、无所有权转移;无效句柄返回 0。
(unsafe { IsWindow(hwnd) }) != 0
}
/// 把整窗 α 下发到窗口。
///
/// `alpha` 一般直接来自 [`super::super::effective_window_alpha`](`None` = 拒绝整窗穿透)。
@@ -215,6 +229,12 @@ pub fn apply_window_alpha(hwnd: isize, alpha: Option<f64>) -> AlphaOutcome {
#[cfg(target_os = "windows")]
#[link(name = "user32")]
extern "system" {
/// `IsWindow`:句柄是否指向一个存在的窗口。
///
/// 为什么需要它(M100 r1):`GetWindowLongPtrW` 对**无效句柄**返回 0,与「扩展样式全 0」
/// 不可区分。取证探针要分「拿不到」与「读到了没有这一位」,所以先验一次句柄。
fn IsWindow(hwnd: isize) -> i32;
/// `SetLayeredWindowAttributes`:窗口必须已带 `WS_EX_LAYERED`,α 才生效。
///
/// 签名照 Win32 头文件:`BOOL SetLayeredWindowAttributes(HWND, COLORREF, BYTE, DWORD)`。
@@ -1,11 +1,20 @@
//! 取证用的**扩展样式探针**(M100 r1 P2-2):这个窗口是不是「点击穿透」。
//!
//! 为什么单开一个文件:`transparency.rs` 撞 400 行硬线(361 → 447)。`unsafe` 的**放行属性仍只有
//! `transparency.rs` 顶部那一个**——lint 级别沿模块树继承,子模块直接继承父模块的
//! `#![allow(unsafe_code)]`,所以本文件**不许**再写那行属性(CI 的 `unsafe-scope` 判据是
//! 「带放行属性的文件集合恰好等于 `transparency.rs`」)。
//! ## 本文件零 `unsafe`、零 `extern`
//!
//! 判据来源:winit 0.30 在 Windows 把 `set_cursor_hittest(false)` 落成
//! 全仓 `unsafe` 只允许出现在 [`super`](`transparency.rs`)一个文件里,判据是
//! 「**带放行属性**的文件集合恰好等于它」。所以探针需要的 FFI 一律由 `transparency.rs` 提供
//! **安全包装**([`super::window_exists`] / [`super::raw_ex_style`]),本文件只做纯判断、
//! 三态映射与测试。
//!
//! ⚠️ **别把 FFI 写回来**(M100 r1 复审实测抓过一次):lint 级别沿模块树继承,所以在这里写
//! 一个 `unsafe` 块 + `extern` 声明也**编得过**,`unsafe-scope` 门禁也照样绿(它只数「带放行
//! 属性的文件」)——但「全仓唯一允许 unsafe 的文件」这个性质就破了。
//! 属性的作用是可审计性,不是给 CI 看的。
//!
//! ## 判据来源
//!
//! winit 0.30 在 Windows 把 `set_cursor_hittest(false)` 落成
//! `WS_EX_TRANSPARENT | WS_EX_LAYERED`(`window_state.rs`)。所以读回这一位,就是
//! 「取证窗口真的把命中测试关掉了」的 OS 侧证据——比「出图 hash 不变」有判别力得多
//! (实测:同 argv 开/关穿透,hash 完全相同)。
@@ -32,6 +41,12 @@ pub const fn is_click_through_style(ex_style: isize) -> bool {
/// **不许记成 `off`**——「拿不到」和「没有」是两件事,混为一谈就是假绿(本项目在别处栽过:
/// 扫描读不全时报「没有」)。所以这里宁可 `None`,也不用「读失败的 0」冒充「没这一位」。
///
/// ## 为什么本文件零 `unsafe`、零 `extern`
///
/// `unsafe` 全仓只在 [`super`](`transparency.rs`)那一个文件里。探针需要的 FFI
/// (`IsWindow` / `GetWindowLongPtrW`)都由 `super` 提供安全包装
/// ([`super::window_exists`] / [`super::raw_ex_style`]),本文件只做**纯判断**。
///
/// ## 用途
///
/// 出图时把它打进日志(`pages::harness` 的 `[caps] passthrough_ext=…`),于是「取证窗口到底
@@ -39,11 +54,7 @@ pub const fn is_click_through_style(ex_style: isize) -> bool {
#[cfg(target_os = "windows")]
#[must_use]
pub fn click_through(hwnd: isize) -> Option<bool> {
if hwnd == 0 {
return None;
}
// SAFETY: `IsWindow` 只按值接受句柄,不持有指针、无所有权转移;无效句柄返回 0。
if unsafe { IsWindow(hwnd) } == 0 {
if hwnd == 0 || !super::window_exists(hwnd) {
return None;
}
Some(is_click_through_style(raw_ex_style(hwnd)))
@@ -56,16 +67,6 @@ pub fn click_through(_hwnd: isize) -> Option<bool> {
None
}
#[cfg(target_os = "windows")]
#[link(name = "user32")]
extern "system" {
/// `IsWindow`:句柄是否指向一个存在的窗口(读扩展样式前的门槛)。
///
/// 为什么要先问一句:`GetWindowLongPtrW` 对无效句柄返回 0,与「扩展样式全 0」不可区分——
/// 不先验一次,[`click_through`] 就会把「读不到」说成「没开穿透」。
fn IsWindow(hwnd: isize) -> i32;
}
#[cfg(test)]
mod tests {
use super::{click_through, is_click_through_style, WS_EX_TRANSPARENT};