//go:build windows package procscan import ( "strings" "syscall" "unsafe" "golang.org/x/sys/windows" ) // Snapshot returns a map of PID → exe basename for every running // process whose exe name (case-insensitively) matches one of the // names in `targets`. Pass an empty/nil targets to capture all // processes (useful for debugging). func Snapshot(targets []string) (map[uint32]string, error) { snap, err := windows.CreateToolhelp32Snapshot(windows.TH32CS_SNAPPROCESS, 0) if err != nil { return nil, err } defer windows.CloseHandle(snap) var entry windows.ProcessEntry32 entry.Size = uint32(unsafe.Sizeof(entry)) if err := windows.Process32First(snap, &entry); err != nil { return nil, err } wantAll := len(targets) == 0 wantSet := make(map[string]struct{}, len(targets)) for _, n := range targets { wantSet[strings.ToLower(n)] = struct{}{} } out := map[uint32]string{} for { exeName := syscall.UTF16ToString(entry.ExeFile[:]) if wantAll { out[entry.ProcessID] = exeName } else if _, ok := wantSet[strings.ToLower(exeName)]; ok { out[entry.ProcessID] = exeName } err := windows.Process32Next(snap, &entry) if err != nil { if err == syscall.ERROR_NO_MORE_FILES { break } return nil, err } } return out, nil } // DiffPIDs reports which PIDs are added (in cur but not prev) and // removed (in prev but not cur). Used by the engine's procscan ticker // to decide whether to rebuild the WinDivert filter. func DiffPIDs(prev, cur map[uint32]string) (added, removed []uint32) { for pid := range cur { if _, ok := prev[pid]; !ok { added = append(added, pid) } } for pid := range prev { if _, ok := cur[pid]; !ok { removed = append(removed, pid) } } return }