开机延时启动程序

1.原始需求

我比较懒希望每天早上到公司以后电脑已经开启,且各种软件都已经打开(因为有强迫症,头天晚上必须关电脑)。因此我把主机BIOS设置了来电就开机,买了一个智能插座配置工作日早上9点上电,晚上23点断电,并且设置了电脑开机免输入密码登录。这样就做到了早上自动开机的需求,但是我又不想搞很多开机启动项,而且开机启动项会拖慢开机速度。因此我自己写了一个开机后延时启动的小程序。

2.展示程序
package main

import (
    "encoding/json"
    "flag"
    "fmt"
    "io/ioutil"
    "log"
    "os"
    "os/exec"
    "path/filepath"
    "strings"
    "sync"
    "time"

    "golang.org/x/sys/windows/registry"
)

type DelayStart struct {
    Wait     bool     `json:"wait"`     // 是否等待运行结束
    Explorer bool     `json:"explorer"` // 是否用explorer启动
    Path     string   `json:"path"`     // 程序路径
    Argv     string   `json:"argv"`     // 程序命令行参数
    Env      []string `json:"env"`      // 增加的环境变量
    Dir      string   `json:"dir"`      // 起始路径
    Delay    uint64   `json:"delay"`    // 延时秒数
}

const (
    regPath = `SOFTWARE\Microsoft\Windows\CurrentVersion\Run`
    regName = "StartDelay"
)

var explorer string // explorer.exe path

func main() {
    regCtl := flag.String("reg", "", "[Add|Del] Startup")
    config := flag.String("c", "", "config file")
    flag.Usage = func() {
        fmt.Printf(`Usage of %s:
  -c string
        config file
  -reg string
        [Add|Del] Startup

Example config.json:
[
  {
    "wait": true,
    "explorer": false,
    "path": "C:\\start.exe",
    "argv": "-c config.json",
    "env": [
      "env=abc"
    ],
    "dir": "C:\\",
    "delay": 5
  }
]`, os.Args[0])
    }
    flag.Parse()
    if *regCtl != "" {
        k, err := registry.OpenKey(registry.CURRENT_USER, regPath, registry.ALL_ACCESS)
        if err != nil {
            registry.CreateKey(registry.CURRENT_USER, regPath, registry.ALL_ACCESS)
            k, err = registry.OpenKey(registry.CURRENT_USER, regPath, registry.ALL_ACCESS)
            if err != nil { // 创建后重新打开
                log.Fatal(err)
            }
        }
        defer k.Close()

        if strings.ToLower(*regCtl) == "del" {
            if err = k.DeleteValue(regName); err != nil {
                log.Fatal(err)
            }
            return
        }

        localPath, err := filepath.Abs(os.Args[0])
        if err != nil {
            log.Fatal(err)
        }
        startUp := "\"" + localPath + "\""
        if *config != "" {
            startUp += " -c \"" + *config + "\""
        }
        if err = k.SetStringValue(regName, startUp); err != nil {
            log.Fatal(err)
        }
        return
    }

    if *config != "" {
        explorer = filepath.Join(os.Getenv("SystemRoot"), "explorer.exe")
        _, err := os.Stat(explorer) // exist
        if err != nil && os.IsNotExist(err) {
            log.Fatal(explorer, "not exist")
        }

        byt, err := ioutil.ReadFile(*config)
        if err != nil {
            log.Fatal(err)
        }
        var cnf []DelayStart
        if err = json.Unmarshal(byt, &cnf); err != nil {
            log.Fatal(err)
        }

        wg := new(sync.WaitGroup)
        for _, v := range cnf {
            if strings.ToLower(filepath.Ext(v.Path)) == ".exe" {
                if _, err = os.Stat(v.Path); err == nil || os.IsExist(err) {
                    wg.Add(1)
                    go startExe(v, wg)
                }
            }
        }
        wg.Wait()
    }
}

// 延迟指定时间启动
func startExe(cnf DelayStart, wg *sync.WaitGroup) {
    defer wg.Done() // done one task
    time.Sleep(time.Second * time.Duration(cnf.Delay))
    var c *exec.Cmd
    if cnf.Explorer { // 用这个打开没有参数,如果需要可建立快捷方式
        c = exec.Command(explorer, cnf.Path)
    } else {
        c = exec.Command(cnf.Path, strings.Fields(cnf.Argv)...)
    }

    log.Println(c.Args)  // 打印执行程序
    c.Env = os.Environ() // 当前环境变量给子进程
    for _, v := range cnf.Env {
        if strings.Index(v, "=") > 0 {
            c.Env = append(c.Env, v) // 新增环境变量
        }
    }
    s, err := os.Stat(cnf.Dir)
    if (err == nil || os.IsExist(err)) && s.IsDir() {
        c.Dir = cnf.Dir // 起始路径
    }

    if err = c.Start(); err != nil {
        log.Println(err)
    } else if !cnf.Explorer && cnf.Wait {
        if err = c.Wait(); err != nil {
            log.Println(err)
        }
    } // 只在非Explorer执行时判断是否需要等待
}
3.用法
1.这个程序可以加入开机启动
# .\StartDelay.exe -h
Usage of .\StartDelay.exe:
  -c string
        config file
  -reg string
        [Add|Del] Startup
当执行.\StartDelay.exe -reg Add -c cnf.json
就会在注册表里面添加开机启动项
2.该程序需要的配置文件示例,会按照配置一个一个打开相应程序,delay单位是秒
[
  {
    "path": "E:\\Program_Files\\explorer.exe",
    "argv": "E:\\",
    "delay": 30
  },
  {
    "path": "E:\\Program_Files\\chrome.exe",
    "argv": "https://www.baidu.com",
    "delay": 40
  }
]

captcha