错误信息解码与窗口列表提示
This commit is contained in:
parent
3a9b4fa3c7
commit
e1f162aa82
@ -78,6 +78,16 @@ function encoded(command: string): string {
|
||||
return Buffer.from(command, "utf16le").toString("base64");
|
||||
}
|
||||
|
||||
/** 从 PowerShell 错误输出里提取 CLIXML 段的真实错误文本(否则显示为乱码转义序列) */
|
||||
function decodeCliXml(detail: string): string {
|
||||
const lines = [...detail.matchAll(/<S S="Error">(.*?)<\/S>/gs)].map((m) => m[1]);
|
||||
if (lines.length === 0) return detail;
|
||||
// 只留「+ 类别/错误消息」首行, 去掉位置堆栈噪声; _xHHHH_ 是 CLIXML 转义
|
||||
const decoded = lines.join("\n").replace(/_x([0-9A-Fa-f]{4})_/g, (_, h) => String.fromCharCode(parseInt(h, 16)));
|
||||
const first = decoded.split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("所在位置") && !l.startsWith("+") && !l.startsWith("~~") && !l.includes("CategoryInfo") && !l.includes("FullyQualifiedErrorId") && !l.startsWith("<Objs") && !l.startsWith("#<"));
|
||||
return first[0] || decoded.split("\n")[0].trim() || detail;
|
||||
}
|
||||
|
||||
export async function powershell(command: string, timeout = 30000): Promise<string> {
|
||||
try {
|
||||
// Windows PowerShell 的默认输出编码依机器代码页变化;Node 按 UTF-8 解码管道。
|
||||
@ -89,7 +99,8 @@ export async function powershell(command: string, timeout = 30000): Promise<stri
|
||||
});
|
||||
return String(result.stdout || "").trim();
|
||||
} catch (error) {
|
||||
const detail = error instanceof Error ? error.message : String(error);
|
||||
const raw = error instanceof Error ? error.message : String(error);
|
||||
const detail = decodeCliXml(raw);
|
||||
throw new RuntimeError("desktop_command_failed", `桌面操作失败:${detail}`, { detail });
|
||||
}
|
||||
}
|
||||
@ -170,8 +181,9 @@ const mouseRoll: CapabilityHandler = async (_ctx, node, args) => {
|
||||
/** 把匹配标题的窗口带到前台;多招式依次兜底(应用点击「运行」后自身是前台,
|
||||
* Windows 前台锁定策略会拒绝普通 SetForegroundWindow,最小化再恢复可绕过) */
|
||||
function activateWindowScript(selector: string): string {
|
||||
const safeTitle = selector.replace(/'/g, "''");
|
||||
return `$p = Get-Process | Where-Object { $_.MainWindowTitle -and $_.MainWindowTitle -like ${psString(`*${selector}*`)} } | Select-Object -First 1
|
||||
if (-not $p) { throw '找不到窗口:${selector.replace(/'/g, "''")}' }
|
||||
if (-not $p) { $vis = (Get-Process | Where-Object { $_.MainWindowTitle } | Select-Object -First 12 | ForEach-Object { '『' + $_.MainWindowTitle + '』' }) -join ' '; throw ('找不到窗口:${safeTitle}。当前可见窗口标题: ' + $vis) }
|
||||
Add-Type -MemberDefinition '[DllImport("user32.dll")] public static extern IntPtr GetForegroundWindow(); [DllImport("user32.dll")] public static extern bool ShowWindow(IntPtr h, int cmd); [DllImport("user32.dll")] public static extern bool IsIconic(IntPtr h); [DllImport("user32.dll")] public static extern bool SetForegroundWindow(IntPtr h); [DllImport("user32.dll")] public static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, UIntPtr dwExtraInfo); [DllImport("user32.dll")] public static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr pid); [DllImport("user32.dll")] public static extern bool AttachThreadInput(uint a, uint b, bool attach); [DllImport("user32.dll")] public static extern void SwitchToThisWindow(IntPtr hWnd, bool fAltTab); [DllImport("kernel32.dll")] public static extern uint GetCurrentThreadId();' -Name RpaFocus2 -Namespace WinRpaFocus2 | Out-Null
|
||||
$h = $p.MainWindowHandle
|
||||
if ([WinRpaFocus2.RpaFocus2]::IsIconic($h)) { [void][WinRpaFocus2.RpaFocus2]::ShowWindow($h, 9); Start-Sleep -Milliseconds 150 }
|
||||
|
||||
Loading…
Reference in New Issue
Block a user