| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798 |
- //go:build windows
- package main
- import (
- "os"
- "os/exec"
- "strconv"
- "syscall"
- "unsafe"
- "golang.org/x/sys/windows"
- )
- const createNoWindow = 0x08000000
- // hideWindow 让子进程完全不显示终端窗口(CREATE_NO_WINDOW + HideWindow)。
- func hideWindow(cmd *exec.Cmd) {
- if cmd.SysProcAttr == nil {
- cmd.SysProcAttr = &syscall.SysProcAttr{}
- }
- cmd.SysProcAttr.HideWindow = true
- cmd.SysProcAttr.CreationFlags |= createNoWindow
- }
- // killTree 强制结束进程树(含 node 派生的子进程)。
- func killTree(pid int) error {
- if pid <= 0 {
- return nil
- }
- cmd := exec.Command("taskkill", "/PID", strconv.Itoa(pid), "/T", "/F")
- hideWindow(cmd)
- return cmd.Run()
- }
- // processAlive 判断进程是否仍在运行。
- func processAlive(pid int) bool {
- if pid <= 0 {
- return false
- }
- h, err := windows.OpenProcess(windows.PROCESS_QUERY_LIMITED_INFORMATION, false, uint32(pid))
- if err != nil {
- return false
- }
- defer windows.CloseHandle(h)
- var code uint32
- if err := windows.GetExitCodeProcess(h, &code); err != nil {
- return false
- }
- return code == 259 // STILL_ACTIVE
- }
- var (
- kernel32 = windows.NewLazySystemDLL("kernel32.dll")
- procCreateMutex = kernel32.NewProc("CreateMutexW")
- )
- // singleInstance 基于命名互斥体的单实例保护。
- type singleInstance struct {
- handle windows.Handle
- }
- func acquireSingleInstance(name string) (*singleInstance, bool) {
- n, err := windows.UTF16PtrFromString(name)
- if err != nil {
- return nil, true
- }
- h, _, callErr := procCreateMutex.Call(0, 0, uintptr(unsafe.Pointer(n)))
- if h == 0 {
- return nil, true // 创建失败时放行,避免误伤
- }
- if errno, ok := callErr.(syscall.Errno); ok && errno == syscall.ERROR_ALREADY_EXISTS {
- _ = windows.CloseHandle(windows.Handle(h))
- return nil, false
- }
- return &singleInstance{handle: windows.Handle(h)}, true
- }
- func (s *singleInstance) release() {
- if s != nil && s.handle != 0 {
- _ = windows.CloseHandle(s.handle)
- s.handle = 0
- }
- }
- // attachConsole 让 windowsgui 子系统程序能输出到调用它的终端(CLI 子命令用)。
- func attachConsole() {
- const attachParentProcess = 0xFFFFFFFF
- procAttach := kernel32.NewProc("AttachConsole")
- ret, _, _ := procAttach.Call(uintptr(attachParentProcess))
- if ret == 0 {
- return
- }
- if f, err := os.OpenFile("CONOUT$", os.O_WRONLY, 0); err == nil {
- os.Stdout = f
- os.Stderr = f
- }
- }
|