
本文介绍在 Go 语言中,如何在 Windows 平台通过可执行文件名(如 "notepad.exe")查找对应进程的 PID,借助 Windows API 的 CreateToolhelp32Snapshot 等函数实现跨进程枚举与精确匹配。
本文介绍在 go 语言中,如何在 windows 平台通过可执行文件名(如 "notepad.exe")查找对应进程的 pid,借助 windows api 的 `createtoolhelp32snapshot` 等函数实现跨进程枚举与精确匹配。
在 Go 标准库中,os.FindProcess(pid) 仅支持通过已知 PID 获取进程句柄,不提供按名称反查 PID 的能力。要在 Windows 下实现“由进程名查 PID”,必须调用底层 Windows API —— 这并非 Go 运行时原生支持的功能,而是需要借助 golang.org/x/sys/windows 包封装的系统调用接口。
核心思路是:
- 创建进程快照(CreateToolhelp32Snapshot),类型为 TH32CS_SNAPPROCESS;
- 使用 Process32First 获取首个进程条目;
- 循环调用 Process32Next 遍历所有进程,直至返回 ERROR_NO_MORE_FILES;
- 对每个进程的 ExeFile 字段(UTF-16 编码的可执行文件名)进行安全解码与大小写不敏感比对;
- 返回匹配进程的 PID(及其它元信息)。
以下为完整、健壮的实现示例(含错误处理与内存安全):
package main
import (
"strings"
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
const TH32CS_SNAPPROCESS = 0x00000002
type WindowsProcess struct {
ProcessID int
ParentProcessID int
Exe string
}
func GetProcesses() ([]WindowsProcess, error) {
handle, err := windows.CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
if err != nil {
return nil, err
}
defer windows.CloseHandle(handle)
var entry windows.ProcessEntry32
entry.Size = uint32(unsafe.Sizeof(entry))
err = windows.Process32First(handle, &entry)
if err != nil {
return nil, err
}
var results []WindowsProcess
for {
results = append(results, newWindowsProcess(&entry))
err = windows.Process32Next(handle, &entry)
if err != nil {
if err == syscall.ERROR_NO_MORE_FILES {
break // 遍历完成
}
return nil, err
}
}
return results, nil
}
func FindProcessByName(name string) (*WindowsProcess, error) {
procs, err := GetProcesses()
if err != nil {
return nil, err
}
lowerName := strings.ToLower(name)
for _, p := range procs {
if strings.ToLower(p.Exe) == lowerName {
return &p, nil
}
}
return nil, nil // 未找到,返回 nil 而非 error(语义更清晰)
}
func newWindowsProcess(e *windows.ProcessEntry32) WindowsProcess {
// 安全截取 ExeFile 中以 \0 结尾的 UTF-16 字符串
end := 0
for end < len(e.ExeFile) && e.ExeFile[end] != 0 {
end++
}
exeStr := syscall.UTF16ToString(e.ExeFile[:end])
return WindowsProcess{
ProcessID: int(e.ProcessID),
ParentProcessID: int(e.ParentProcessID),
Exe: exeStr,
}
}
// 使用示例:
func main() {
if p, err := FindProcessByName("notepad.exe"); err != nil {
panic(err)
} else if p != nil {
println("Found notepad.exe with PID:", p.ProcessID)
} else {
println("notepad.exe is not running.")
}
}⚠️ 注意事项:
- 必须导入 golang.org/x/sys/windows(非标准库,需 go get 安装);
- ProcessEntry32.ExeFile 是固定长度的 []uint16(通常 260),需手动定位 \0 终止符,避免 UTF16ToString 解码越界;
- 进程名比对建议统一转小写(如 notepad.exe 与 NOTEPAD.EXE 均匹配);
- 该方法仅适用于 Windows;若需跨平台,请结合 runtime.GOOS 分支处理(Linux/macOS 可读 /proc 或 ps 命令);
- 遍历过程无特权要求,普通用户权限即可运行。
此方案稳定可靠,已被用于生产级进程监控工具中。掌握它,你便拥有了在 Windows Go 程序中精准定位目标进程的能力。


















