50 lines
5.6 KiB
Markdown
50 lines
5.6 KiB
Markdown
# PowerShell → C# 移植对照表(RPA 桌面驱动 → windows-runner actuate)
|
||
|
||
来源:`packages/rpa-core/src/driver/windows/windows-driver.ts`(269 行,内嵌 PowerShell)
|
||
目标:对面 `code/backend/services/windows-runner/native/`(原型见本目录 `native/`)
|
||
|
||
## 一、原语级映射
|
||
|
||
| RPA 侧 PowerShell 原语 | 用途(驱动行号) | C# 等价物(原型落点) | 语义保真要点 |
|
||
|---|---|---|---|
|
||
| `SetCursorPos(x,y)` | moveTo / click / drag / moveSmooth(L142,150,158,173) | `NativeInput.SetCursorPos` | 物理像素;进程入口声明 Per-Monitor V2 DPI(对应 PS 每脚本的 `SetProcessDpiAwarenessContext(-4)`,一次声明进程级生效) |
|
||
| `mouse_event(flags,0,0,data,0)` down/up | click / drag(L150,158) | `SendInput`(MOUSEEVENTF_LEFTDOWN=0x0002 / LEFTUP=0x0004 / RIGHTDOWN=0x0008 / RIGHTUP=0x0010) | SendInput 是 mouse_event 的现代等价;标志位一一对应。双击=repeats 2,settleMs 逐次保留 |
|
||
| `mouse_event(0x0800,...,amount)` | scroll(L161) | `SendInput` + MOUSEEVENTF_WHEEL,mouseData=有符号 delta | 负值向下滚,`unchecked((uint)amount)` 保持位型一致 |
|
||
| `GetCursorPos` + JS `mousePath` 插值 | moveSmooth(L163-174) | `ActuateService.SmoothMovePath`(公式逐行移植) | 缓入缓出二次曲线 + 垂直抖动 `sin(i*12.9898)*43758.5453 % 1`;stepCount=clamp(distance/12, 6, 50);delay=clamp(1500/speed, 4, 80)ms。JS 与 C# 的 `%` 对负数同为保号语义,公式无漂移 |
|
||
| `Set-Clipboard` + `SendWait('^v')` | keyboard clipboard 模式(L183) | `Clipboard.SetDataObject(text, true)` + `SendKeys.SendWait("^v")` | 120ms 间隙保留;STA 已由对面 `[STAThread]` 保证 |
|
||
| `SendWait($c)` 逐字符循环 | keyboard manual 模式(L188) | 逐字符 `SendKeys.SendWait(Escape(ch))` + `Thread.Sleep(intervalMs)` | intervalMs 逐字符保留 |
|
||
| `SendWait(escaped)` 整段 | keyboard 默认模式(L192) | `SendKeys.SendWait(escaped)` | `sendKeysEscape` 字符集 `+^%~(){}[]` → `{+}` 等花括号转义,逐字符同规则移植(`ActuateService.EscapeSendKeys`) |
|
||
| `activateWindowScript` **抢前台五招兜底** | focus(L73-105,键盘与激活共用) | `NativeInput.FocusChain`(逐行移植) | 顺序与睡眠严格保留:①IsIconic→SW_RESTORE(9)+150ms ②SwitchToThisWindow+150ms ③ALT(0x12 down/up)+SetForegroundWindow+200ms ④AttachThreadInput 对线程+SetForegroundWindow+200ms ⑤SW_MINIMIZE(6)+150ms→SW_RESTORE(9)+300ms ⑥仍失败→稳定错误码 `focus_failed`(PS 版走 `RPA_ERROR::` stdout 通道) |
|
||
| `Get-Process | MainWindowTitle -like *title*` | 窗口查找(L60-68 等) | `Win32 EnumWindows` + 精确标题 + PID 回查进程名 + Session 校验(复用对面 observe 的 SelectWindow 模式) | **唯一语义变更**,见下节 1 |
|
||
| `GetWindowRect` + JSON 输出 | windowObject / foregroundPosition(L66,213) | `NativeWindows.GetWindowRect`(对面已有,直接复用) | RECT right/bottom → width/height 换算保持 |
|
||
| `ShowWindow(h, 3/6/9/cmd)` | activate/maximize / setState / 五招内部(L203,224) | `NativeInput.ShowWindow` | 命令值原样透传 |
|
||
| `SetWindowPos(h,0,x,y,w,h,4)` | setSize / setPos(L227,231) | `NativeInput.SetWindowPos` | flags=4(SWP_NOZORDER)原样保留;尺寸>0 校验保留(L230) |
|
||
| `Process.CloseMainWindow()` | close(L221) | `PostMessage(h, WM_CLOSE=0x0010)` | 等价语义(礼貌关闭,不杀进程) |
|
||
| `System.Windows.Forms.Screen.PrimaryScreen.Bounds` | screen.size(L246) | 不移植——observe op 的 CoordinateSpace 已携带窗口矩形+DPI | 避免重复采集 |
|
||
|
||
## 二、必须知道的三处语义差异(宿主适配层负责弥合)
|
||
|
||
1. **窗口匹配从模糊变精确**。PS 版 `Get-Process -like *title*` 是包含匹配;对面安全政策要求 WindowTitle 与 AllowedWindows **精确相等**(模糊匹配会把同名网页/提示框误当目标)。弥合方式:TS 宿主适配器先用 observe 解析出精确标题与进程名,再发起 actuate 请求——RPA 能力层(`window.findByTitle`)语义不变,只是解析下沉到宿主。
|
||
2. **进程模型从"每命令一进程"变"单请求单响应"**。PS 版每个原语起一个 powershell.exe;C# 版一次请求一次响应、宿主超时杀进程(对面现行架构)。RPA 流程里相邻原语本来也无状态依赖(除句柄传递,改由标题精确匹配承担),语义等价。注意:宿主超时必须覆盖 moveSmooth 最坏情况(约 4s)+ 两次证据截图。
|
||
3. **副作用证据从无到有**。PS 版动作无留痕;C# 版按对面证据体系在动作**前后各截一张**目标窗口 PNG(PrintWindow,SHA-256 落盘,默认 secret)——这是对面 capability-gateway 审计链要求的,属于增强而非等价项。
|
||
|
||
## 三、稳定错误码映射(PS 侧 → C# 侧)
|
||
|
||
| PS 侧失败 | C# actuate 稳定错误码 |
|
||
|---|---|
|
||
| `找不到窗口:<title>`(throw/RPA_ERROR) | `window_not_found`(无候选)/ `window_ambiguous`(多候选,对面已有语义)/ `window_not_allowed`(不在白名单) |
|
||
| `无法把窗口带到前台…`(五招全失败) | `focus_failed` |
|
||
| 输入注入 Win32 失败 | `input_failed` |
|
||
| 证据截图失败/空白 | `capture_unavailable`(沿用对面现有码) |
|
||
| 政策校验失败 | `policy_invalid` / `desktop_session_mismatch`(沿用对面现有码) |
|
||
|
||
## 四、开关映射:mouse_event → SendInput 标志位
|
||
|
||
| mouse_event flag | SendInput MOUSEEVENTF | 用途 |
|
||
|---|---|---|
|
||
| 0x0002 | LEFTDOWN | 左键按下 |
|
||
| 0x0004 | LEFTUP | 左键抬起 |
|
||
| 0x0008 | RIGHTDOWN | 右键按下 |
|
||
| 0x0010 | RIGHTUP | 右键抬起 |
|
||
| 0x0800 | WHEEL | 滚轮(data=delta,120 的倍数) |
|