package main import ( "errors" "fmt" "os" "path/filepath" "strings" "golang.org/x/sys/windows" "golang.org/x/sys/windows/registry" ) var keyPath = `Software\Microsoft\Windows\CurrentVersion\Run` // resolveExePath 优先用 os.Executable(),回退到 os.Args[0] // 这能正确处理通过快捷方式 / PATH 启动时 os.Args[0] 不是绝对路径的情况 func resolveExePath() string { if exe, err := os.Executable(); err == nil { if abs, err := filepath.Abs(exe); err == nil { return abs } return exe } abs, _ := filepath.Abs(os.Args[0]) return abs } // 设置开机自启动 // exePath 传入会被忽略,内部一律以 os.Executable() 为准 func setAutoStart(appName string, exePath string) error { key, _, err := registry.CreateKey(registry.CURRENT_USER, keyPath, registry.ALL_ACCESS) // 当前用户登录后启动 //key, _, err := registry.CreateKey(registry.LOCAL_MACHINE, keyPath, registry.ALL_ACCESS) // 登录前启动(需要管理员权限) if err != nil { if errors.Is(err, windows.ERROR_ACCESS_DENIED) { return err } return fmt.Errorf("无法打开注册表键: %v", err) } defer key.Close() // 使用真实的 exe 路径而不是 os.Args[0],避免相对路径 absPath := resolveExePath() if absPath == "" { return fmt.Errorf("无法确定可执行文件路径") } args := getArgs() // 路径包含空格时需要加引号 value := fmt.Sprintf(`"%s"`, absPath) if args != "" { value = value + " " + args } err = key.SetStringValue(appName, value) if err != nil { return fmt.Errorf("写入注册表失败: %v", err) } return nil } // 移除开机自启动 func removeAutoStart(appName string) error { key, err := registry.OpenKey(registry.CURRENT_USER, keyPath, registry.ALL_ACCESS) //key, err := registry.OpenKey(registry.LOCAL_MACHINE, keyPath, registry.ALL_ACCESS) if err != nil { if errors.Is(err, windows.ERROR_ACCESS_DENIED) { return err } return fmt.Errorf("无法打开注册表键: %v", err) } defer key.Close() err = key.DeleteValue(appName) if err != nil { return fmt.Errorf("删除注册表项失败: %v", err) } return nil } // 检查注册表启动项 func isInRegistry(appName string) (bool, error) { // 检查当前用户注册表 userKey, err := registry.OpenKey(registry.CURRENT_USER, keyPath, registry.QUERY_VALUE) if err == nil { defer userKey.Close() _, _, err := userKey.GetStringValue(appName) if err == nil { return true, nil } } // 检查本地机器注册表(需要管理员权限) //systemKey, err := registry.OpenKey(registry.LOCAL_MACHINE, keyPath, registry.QUERY_VALUE) //if err == nil { // defer systemKey.Close() // _, _, err := systemKey.GetStringValue(appName) // if err == nil { // return true, nil // } //} return false, nil } // 综合检查开机启动状态 func isAutoStartEnabled(appName string) bool { // 检查注册表 if reg, _ := isInRegistry(appName); reg { return true } return false } func getArgs() string { // 构建参数字符串(兼容含空格的参数) var argsBuilder strings.Builder for _, arg := range os.Args[1:] { if strings.ContainsAny(arg, " \t") { argsBuilder.WriteString(fmt.Sprintf(`"%s" `, arg)) } else { argsBuilder.WriteString(arg + " ") } } return strings.TrimSpace(argsBuilder.String()) }