mirror of
https://github.com/AtomUI/AtomUI.git
synced 2026-10-26 11:10:34 +08:00
152 lines
4.0 KiB
Markdown
152 lines
4.0 KiB
Markdown
# AtomUI.Native — Windows 平台 API 文档
|
||
|
||
## 概述
|
||
|
||
Windows 平台通过 `user32.dll` 的窗口扩展样式(Extended Window Styles)机制实现窗口级鼠标事件穿透。所有 API 均标注 `[SupportedOSPlatform("windows")]`。
|
||
|
||
---
|
||
|
||
## 1. 公共扩展方法
|
||
|
||
### 1.1 SetWindowIgnoreMouseEvents
|
||
|
||
设置窗口是否忽略(穿透)鼠标输入事件。
|
||
|
||
```csharp
|
||
internal static void SetWindowIgnoreMouseEvents(this WindowBase window, bool flag)
|
||
```
|
||
|
||
**参数:**
|
||
|
||
| 参数 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| `window` | `WindowBase` | Avalonia 窗口实例 |
|
||
| `flag` | `bool` | `true` 启用穿透,`false` 禁用穿透 |
|
||
|
||
**异常:**
|
||
|
||
| 异常类型 | 条件 |
|
||
|----------|------|
|
||
| `ArgumentException` | 窗口句柄无效(`IntPtr.Zero`) |
|
||
| `PlatformNotSupportedException` | 当前平台不受支持 |
|
||
|
||
**Windows 实现原理:**
|
||
|
||
通过修改窗口扩展样式(`GWL_EXSTYLE`)中的 `WS_EX_TRANSPARENT` 和 `WS_EX_LAYERED` 位标志:
|
||
|
||
- **启用穿透**:`ExStyle |= (WS_EX_TRANSPARENT | WS_EX_LAYERED)`
|
||
- **禁用穿透**:`ExStyle &= ~(WS_EX_TRANSPARENT | WS_EX_LAYERED)`
|
||
|
||
> ⚠️ `WS_EX_LAYERED` 是 `WS_EX_TRANSPARENT` 生效的前提条件,两者必须同时设置。
|
||
|
||
---
|
||
|
||
### 1.2 IsWindowIgnoreMouseEvents
|
||
|
||
查询窗口当前是否处于鼠标事件穿透状态。
|
||
|
||
```csharp
|
||
internal static bool IsWindowIgnoreMouseEvents(this WindowBase window)
|
||
```
|
||
|
||
**参数:**
|
||
|
||
| 参数 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| `window` | `WindowBase` | Avalonia 窗口实例 |
|
||
|
||
**返回值:**
|
||
|
||
| 类型 | 说明 |
|
||
|------|------|
|
||
| `bool` | `true` 表示窗口正在穿透鼠标事件 |
|
||
|
||
**Windows 实现原理:**
|
||
|
||
读取窗口扩展样式并检查 `WS_EX_TRANSPARENT` 位:
|
||
|
||
```csharp
|
||
(GetWindowLongPtr(handle, GWL_EXSTYLE) & WS_EX_TRANSPARENT) != 0
|
||
```
|
||
|
||
---
|
||
|
||
## 2. P/Invoke 声明
|
||
|
||
> 命名空间:`AtomUI.Native.Windows`
|
||
> 类:`internal static class WindowUtilsInterop`
|
||
> 平台:`[SupportedOSPlatform("windows")]`
|
||
|
||
### 2.1 Win32 函数
|
||
|
||
#### GetWindowLongPtr
|
||
|
||
获取窗口的扩展样式或其他窗口属性。
|
||
|
||
```csharp
|
||
[DllImport("user32.dll", EntryPoint = "GetWindowLongW", SetLastError = true)]
|
||
public static extern long GetWindowLongPtr(IntPtr hWnd, int nIndex);
|
||
```
|
||
|
||
| 参数 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| `hWnd` | `IntPtr` | 窗口句柄 |
|
||
| `nIndex` | `int` | 属性索引(如 `GWL_EXSTYLE = -20`) |
|
||
|
||
**返回值:** 请求的窗口属性值(`long`)。
|
||
|
||
---
|
||
|
||
#### SetWindowLongPtr
|
||
|
||
设置窗口的扩展样式或其他窗口属性。
|
||
|
||
```csharp
|
||
[DllImport("user32.dll", EntryPoint = "SetWindowLongW", SetLastError = true)]
|
||
public static extern long SetWindowLongPtr(IntPtr hWnd, int nIndex, long dwNewLong);
|
||
```
|
||
|
||
| 参数 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| `hWnd` | `IntPtr` | 窗口句柄 |
|
||
| `nIndex` | `int` | 属性索引 |
|
||
| `dwNewLong` | `long` | 新的属性值 |
|
||
|
||
**返回值:** 设置前的旧属性值(`long`)。
|
||
|
||
---
|
||
|
||
### 2.2 常量定义
|
||
|
||
| 常量 | 值 | 类型 | 说明 |
|
||
|------|----|------|------|
|
||
| `GWL_STYLE` | `-16` | `int` | 窗口样式索引 |
|
||
| `GWL_EXSTYLE` | `-20` | `int` | 扩展窗口样式索引 |
|
||
| `WS_EX_TRANSPARENT` | `0x20L` | `long` | 鼠标事件穿透标志位 |
|
||
| `WS_EX_LAYERED` | `0x80000L` | `long` | 分层窗口标志位(穿透的前提条件) |
|
||
|
||
---
|
||
|
||
## 3. 使用示例
|
||
|
||
```csharp
|
||
// 启用窗口鼠标事件穿透
|
||
window.SetWindowIgnoreMouseEvents(true);
|
||
|
||
// 查询是否处于穿透状态
|
||
bool isPassThrough = window.IsWindowIgnoreMouseEvents();
|
||
|
||
// 禁用穿透,恢复正常鼠标交互
|
||
window.SetWindowIgnoreMouseEvents(false);
|
||
```
|
||
|
||
---
|
||
|
||
## 4. 注意事项
|
||
|
||
1. **句柄有效性** — 调用前确保 `window.PlatformImpl?.Handle?.Handle` 不为 `null` 或 `IntPtr.Zero`
|
||
2. **样式组合** — `WS_EX_TRANSPARENT` 必须与 `WS_EX_LAYERED` 同时使用才能实现完整的鼠标穿透
|
||
3. **线程安全** — Win32 窗口操作应在 UI 线程执行
|
||
4. **副作用** — 设置 `WS_EX_LAYERED` 可能影响窗口的渲染行为,对于已经是分层窗口的场景无额外影响
|
||
|