import path from "node:path"; import { register } from "../engine/registry"; import { powershell, psString } from "./desktop"; interface WordHandle { path: string; } function text(args: Record, keys: string[], fallback = ""): string { for (const key of keys) if (args[key] !== undefined && args[key] !== null && args[key] !== "") return String(args[key]); return fallback; } function handlePath(args: Record): string { const raw = args.objWord ?? args.filePath ?? args.path ?? args.file; if (typeof raw === "object" && raw !== null && "path" in raw) return path.resolve(String((raw as WordHandle).path)); return path.resolve(String(raw || "")); } function ensure(value: string, label: string): string { if (!value.trim()) throw new Error(`${label}为空`); return value; } function wordScript(body: string): string { return `$word = $null; $doc = $null; try { $word = New-Object -ComObject Word.Application; $word.Visible = $false; $word.DisplayAlerts = 0; ${body} } finally { if ($doc -ne $null) { try { $doc.Close() } catch {} ; try { [void][Runtime.InteropServices.Marshal]::ReleaseComObject($doc) } catch {} }; if ($word -ne $null) { try { $word.Quit() } catch {} ; try { [void][Runtime.InteropServices.Marshal]::ReleaseComObject($word) } catch {} }; [GC]::Collect(); [GC]::WaitForPendingFinalizers() }`; } register("Word_New", async (_ctx, _node, args) => { const folder = ensure(text(args, ["filePath", "folder", "path"]), "Word目录"); const name = text(args, ["name"], "新建文档.docx"); const filePath = path.resolve(folder, path.extname(name) ? name : `${name}.docx`); await powershell(wordScript(`$doc = $word.Documents.Add(); $doc.SaveAs2(${psString(filePath)}); ${psString(filePath)}`)); return { path: filePath } satisfies WordHandle; }); register("Word_Open", async (_ctx, _node, args) => ({ path: handlePath(args) } satisfies WordHandle)); register("Word_Write", async (_ctx, _node, args) => { const filePath = ensure(handlePath(args), "Word文件路径"); const content = text(args, ["text", "content"]); await powershell(wordScript(`$doc = $word.Documents.Open(${psString(filePath)}); $range = $doc.Content; $range.Collapse(0); $range.InsertAfter(${psString(content)}); $doc.Save()`)); return { path: filePath } satisfies WordHandle; }); register(["Word_Save", "Word_SaveAs"], async (_ctx, _node, args) => ({ path: handlePath(args) } satisfies WordHandle));