//go:build windows package ttslaunch import ( "os/exec" "syscall" ) const ( // createNewProcessGroup 让子进程成为**新进程组**的组长:后端控制台里的 Ctrl+C // 只送给后端自己的进程组,不会连带掐掉 TTS。 createNewProcessGroup = 0x00000200 // createNewConsole 给子进程开**自己的**控制台窗口 —— 与主人「双击一键启动.bat」 // 看到的形态一致(TTS 的日志照常可见,不糊进后端日志),也不受后端控制台关闭影响。 createNewConsole = 0x00000010 ) // shellCommand 构造「解释一个批处理文件」的命令。 // // 为什么必须经 cmd.exe:`.bat` 不是 PE 可执行映像,Windows 内核无法直接 // CreateProcess 起来(要么失败,要么依赖某个 Go 版本碰巧的兼容路径)。这里把脚本 // 路径作为**独立参数**交给 exec.Command —— 绝不自己拼命令行字符串,空格/中文路径 // 的引号由 os/exec 按 Windows 规则处理(主人那个路径含中文,也见过含空格的安装路径)。 func shellCommand(script string) *exec.Cmd { return exec.Command("cmd.exe", "/c", script) } // startDetached 以"脱离后端生命周期"的方式起进程(不接管它的输入输出)。 func startDetached(cmd *exec.Cmd) error { cmd.SysProcAttr = &syscall.SysProcAttr{ CreationFlags: createNewProcessGroup | createNewConsole, } return cmd.Start() }