创建自动运行服务

时间:2018-06-13 20:13:02

标签: windows go service operating-system

操作系统: windows/7/8/8.1/10 32bit

我有一个问题。如何创建一个像autorun一样的服务? 大多数应用程序通过registryC:\Users\Anon\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup自行运行。但有一些是通过服务安装,或者更确切地说是作为服务。 我有一个代码:

package main

import (
    "fmt"
    "strings"
    "time"
    "syscall"

    "golang.org/x/sys/windows/svc"
    "golang.org/x/sys/windows/svc/mgr"
    "golang.org/x/sys/windows/svc/debug"
    "log"
    "os"
    "path/filepath"
    "golang.org/x/sys/windows/svc/eventlog"
)

var elog debug.Log

type myservice struct{}

func (m *myservice) Execute(args []string, r <-chan svc.ChangeRequest, changes chan<- svc.Status) (ssec bool, errno uint32) {
    const cmdsAccepted = svc.AcceptStop | svc.AcceptShutdown | svc.AcceptPauseAndContinue
    changes <- svc.Status{State: svc.StartPending}
    fasttick := time.Tick(500 * time.Millisecond)
    slowtick := time.Tick(2 * time.Second)
    tick := fasttick
    changes <- svc.Status{State: svc.Running, Accepts: cmdsAccepted}
    elog.Info(1, strings.Join(args, "-"))
loop:
    for {
        select {
        case <-tick:
            beep()
            elog.Info(1, "beep")
        case c := <-r:
            switch c.Cmd {
            case svc.Interrogate:
                changes <- c.CurrentStatus
                // Testing deadlock from https://code.google.com/p/winsvc/issues/detail?id=4
                time.Sleep(100 * time.Millisecond)
                changes <- c.CurrentStatus
            case svc.Stop, svc.Shutdown:
                break loop
            case svc.Pause:
                changes <- svc.Status{State: svc.Paused, Accepts: cmdsAccepted}
                tick = slowtick
            case svc.Continue:
                changes <- svc.Status{State: svc.Running, Accepts: cmdsAccepted}
                tick = fasttick
            default:
                elog.Error(1, fmt.Sprintf("unexpected control request #%d", c))
            }
        }
    }
    changes <- svc.Status{State: svc.StopPending}
    return
}

func runService(name string, isDebug bool) {
    var err error
    if isDebug {
        elog = debug.New(name)
    } else {
        elog, err = eventlog.Open(name)
        if err != nil {
            return
        }
    }
    defer elog.Close()

    elog.Info(1, fmt.Sprintf("starting %s service", name))
    run := svc.Run
    if isDebug {
        run = debug.Run
    }
    err = run(name, &myservice{})
    if err != nil {
        elog.Error(1, fmt.Sprintf("%s service failed: %v", name, err))
        return
    }
    elog.Info(1, fmt.Sprintf("%s service stopped", name))
}

func startService(name string) error {
    m, err := mgr.Connect()
    if err != nil {
        return err
    }
    defer m.Disconnect()
    s, err := m.OpenService(name)
    if err != nil {
        return fmt.Errorf("could not access service: %v", err)
    }
    defer s.Close()
    err = s.Start("is", "auto-started")
    if err != nil {
        return fmt.Errorf("could not start service: %v", err)
    }
    return nil
}

func controlService(name string, c svc.Cmd, to svc.State) error {
    m, err := mgr.Connect()
    if err != nil {
        return err
    }
    defer m.Disconnect()
    s, err := m.OpenService(name)
    if err != nil {
        return fmt.Errorf("could not access service: %v", err)
    }
    defer s.Close()
    status, err := s.Control(c)
    if err != nil {
        return fmt.Errorf("could not send control=%d: %v", c, err)
    }
    timeout := time.Now().Add(10 * time.Second)
    for status.State != to {
        if timeout.Before(time.Now()) {
            return fmt.Errorf("timeout waiting for service to go to state=%d", to)
        }
        time.Sleep(300 * time.Millisecond)
        status, err = s.Query()
        if err != nil {
            return fmt.Errorf("could not retrieve service status: %v", err)
        }
    }
    return nil
}

func main() {
    const svcName = "Best Service"

    isIntSess, err := svc.IsAnInteractiveSession()
    if err != nil {
        log.Fatalf("failed to determine if we are running in an interactive session: %v", err)
    }
    if !isIntSess {
        runService(svcName, false)
        return
    }

    /*err = controlService(svcName, svc.Stop, svc.Stopped)
    err = removeService(svcName)*/
    err = installService(svcName, "Best Service")
    runService(svcName, true)

    if err != nil {
        log.Fatalf("failed to %s: %v", svcName, err)
    }
    return
}

func exePath() (string, error) {
    prog := os.Args[0]
    p, err := filepath.Abs(prog)
    if err != nil {
        return "", err
    }
    fi, err := os.Stat(p)
    if err == nil {
        if !fi.Mode().IsDir() {
            return p, nil
        }
        err = fmt.Errorf("%s is directory", p)
    }
    if filepath.Ext(p) == "" {
        p += ".exe"
        fi, err := os.Stat(p)
        if err == nil {
            if !fi.Mode().IsDir() {
                return p, nil
            }
            err = fmt.Errorf("%s is directory", p)
        }
    }
    return "", err
}

func installService(name, desc string) error {
    exepath, err := exePath()
    if err != nil {
        return err
    }
    m, err := mgr.Connect()
    if err != nil {
        return err
    }
    defer m.Disconnect()
    s, err := m.OpenService(name)
    if err == nil {
        s.Close()
        return fmt.Errorf("service %s already exists", name)
    }
    s, err = m.CreateService(name, exepath, mgr.Config{DisplayName: desc, Description: "BB service"}, "is", "auto-started")
    if err != nil {
        return err
    }
    defer s.Close()
    err = eventlog.InstallAsEventCreate(name, eventlog.Error|eventlog.Warning|eventlog.Info)
    if err != nil {
        s.Delete()
        return fmt.Errorf("SetupEventLogSource() failed: %s", err)
    }
    return nil
}

func removeService(name string) error {
    m, err := mgr.Connect()
    if err != nil {
        return err
    }
    defer m.Disconnect()
    s, err := m.OpenService(name)
    if err != nil {
        return fmt.Errorf("service %s is not installed", name)
    }
    defer s.Close()
    err = s.Delete()
    if err != nil {
        return err
    }
    err = eventlog.Remove(name)
    if err != nil {
        return fmt.Errorf("RemoveEventLogSource() failed: %s", err)
    }
    return nil
}

var (
    beepFunc = syscall.MustLoadDLL("user32.dll").MustFindProc("MessageBeep")
)

func beep() {
    beepFunc.Call(0xffffffff)
}

安装了应用程序,每次退出应用程序时服务都会停止。即使在重新启动PC后,我仍然需要服务,并且应用程序已启动。我该怎么办?

3 个答案:

答案 0 :(得分:2)

也许不是实际的,但是在创建服务期间,您应该扩展并传递Config

mgr.Config {DisplayName:desc,StartType:mgr.StartAutomatic}

喜欢这里:

-e

在这里您可以找到所有必需的常量和函数: https://github.com/golang/sys/blob/master/windows/svc/mgr/config.go

答案 1 :(得分:0)

在Windows 10上,转到任务计划程序&gt;任务计划程序库&gt;创建基本任务&gt;触发:计算机启动时&gt;行动:启动一个程序。

运行任务时,请使用以下用户帐户:SYSTEM。

答案 2 :(得分:0)