//go:build windows // 进程树强杀(编程方式, Windows API)——2026-10-09 起替代原 taskkill /F /T 命令行兜底 // (产品红线: 系统操作禁拼 cmd 命令字符串)。 package process import ( "fmt" "unsafe" "golang.org/x/sys/windows" ) // killProcessTree 按 PID 定向结束进程及其全部后代: // Toolhelp32 快照枚举全进程父子关系 → 收集后代(防父子环) → 逐个 OpenProcess+TerminateProcess。 func killProcessTree(root uint32) error { parentOf, err := snapshotParentMap() if err != nil { return err } var pids []uint32 visited := map[uint32]bool{} var visit func(pid uint32) visit = func(pid uint32) { if visited[pid] { return } visited[pid] = true pids = append(pids, pid) for child, parent := range parentOf { if parent == pid { visit(child) } } } visit(root) var firstErr error for _, pid := range pids { h, err := windows.OpenProcess(windows.PROCESS_TERMINATE, false, pid) if err != nil { if firstErr == nil { firstErr = fmt.Errorf("pid=%d OpenProcess: %w", pid, err) } continue } if err := windows.TerminateProcess(h, 1); err != nil { if firstErr == nil { firstErr = fmt.Errorf("pid=%d TerminateProcess: %w", pid, err) } } _ = windows.CloseHandle(h) } return firstErr } // snapshotParentMap 全进程快照: pid → 父 pid。 func snapshotParentMap() (map[uint32]uint32, error) { snap, err := windows.CreateToolhelp32Snapshot(windows.TH32CS_SNAPPROCESS, 0) if err != nil { return nil, fmt.Errorf("CreateToolhelp32Snapshot: %w", err) } defer windows.CloseHandle(snap) parentOf := map[uint32]uint32{} var pe windows.ProcessEntry32 pe.Size = uint32(unsafe.Sizeof(pe)) if err := windows.Process32First(snap, &pe); err != nil { return nil, fmt.Errorf("Process32First: %w", err) } for { parentOf[pe.ProcessID] = pe.ParentProcessID if err := windows.Process32Next(snap, &pe); err != nil { break } } return parentOf, nil }