为了账号安全,请及时绑定邮箱和手机立即绑定

如何运行用Golang编写的应用程序作为Windows服务

如何运行用Golang编写的应用程序作为Windows服务

Go
偶然的你 2022-08-01 16:33:01
我无法使用我使用Win32 api开发的屏幕截图应用程序作为Windows后台服务。我将其作为Windows后台服务安装并运行,到目前为止我没有问题。我的问题:该服务没有给我打印输出。不截取屏幕截图。我尝试制作另一个简单的应用程序。我尝试使用 OutputDebugStringW 函数发送消息,但我的问题没有得到解决。无法使用 Win32 api 开发 Windows 后台应用程序?为什么我会遇到此问题?如何使用win32 api将屏幕截图应用程序作为Windows后台服务运行?我的 Windows 后台服务未生成输出   package main        import (        "fmt"        "log"        "time"            "github.com/checkgo/win"        "github.com/kardianos/service"    )        var logger service.Logger        type program struct {        exit chan struct{}    }        func (p *program) Start(s service.Service) error {        if service.Interactive() {            logger.Info("Running in terminal.")        } else {            logger.Info("Running under service manager.")        }        p.exit = make(chan struct{})            // Start should not block. Do the actual work async.        go p.run()        return nil    }    func (p *program) run() {        logger.Infof("I'm running %v.", service.Platform())        ticker := time.NewTicker(2 * time.Second)        for {            select {            case tm := <-ticker.C:                win.OutputDebugString(fmt.Sprintf("%s : %v", "This is test message", tm))            case <-p.exit:                ticker.Stop()            }        } // link to whaterver image from the web        }    func (p *program) Stop(s service.Service) error {        // Stop should not block. Return with a few seconds.        return nil    }        func main() {        svcConfig := &service.Config{            Name:        "GoServiceExampleSimple",            DisplayName: "Go Service Example",            Description: "This is an example Go service.",        }            prg := &program{}        s, err := service.New(prg, svcConfig)        if err != nil {            log.Fatal(err)        }        logger, err = s.Logger(nil)        if err != nil {            log.Fatal(err)        }        err = s.Run()        if err != nil {            logger.Error(err)        }    }屏幕截图:调试视图和 Windows 服务屏幕捕获
查看完整描述

2 回答

?
慕码人2483693

TA贡献1860条经验 获得超9个赞

如果服务在 LocalSystem 帐户的安全上下文中运行,但不包括SERVICE_INTERACTIVE_PROCESS属性,则它使用以下窗口工作站和桌面:Service-0x0-3e7$\default。此窗口站不是交互式的,因此服务无法显示用户界面。此外,由服务创建的进程无法显示用户界面。

参考:窗口站和桌面创建

交互式窗口站是唯一可以显示用户界面或接收用户输入的窗口站。它被分配给交互式用户的登录会话,并包含键盘、鼠标和显示设备。它总是被命名为“WinSta0”。所有其他窗口站都是非交互式的,这意味着它们无法显示用户界面或接收用户输入。

参考:窗口站

据说您要捕获的屏幕位于交互式窗口站的默认桌面(Winsta0\default)。您可以在 中创建子进程,子进程用于屏幕截图。使用 CreateProcessAsUser 调用服务中的子进程。Winsta0\default

请参阅以下C++代码。虽然这不是一门围棋语言,但我认为熟悉winapi的呼唤就足够了。

DWORD WINAPI ServiceWorkerThread(LPVOID lpParam)

{

    OutputDebugString(_T("My Sample Service: ServiceWorkerThread: Entry"));

    WCHAR station[] = L"Winsta0\\default";

    SECURITY_ATTRIBUTES saAttr;

    saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);

    saAttr.bInheritHandle = TRUE;

    saAttr.lpSecurityDescriptor = NULL;

     

    STARTUPINFO si;

    ZeroMemory(&si, sizeof(STARTUPINFO));

    si.cb = sizeof(STARTUPINFO);

    si.lpDesktop = station;

    si.dwFlags = STARTF_USESTDHANDLES;

    PROCESS_INFORMATION pi;


    HANDLE hToken;

    bool err = WTSQueryUserToken(WTSGetActiveConsoleSessionId(), &hToken);

    WCHAR path[] = L"D:\\child.exe";  //child.exe is used to take screenshots

    if (CreateProcessAsUser(hToken, path, NULL, 0, 0, true, CREATE_NO_WINDOW, 0, 0, &si, &pi))

    {

        ...


查看完整回答
反对 回复 2022-08-01
?
慕盖茨4494581

TA贡献1850条经验 获得超11个赞

使用CreateProcessAsUser函数解决。

我用来解决问题的GOO源代码。

Windows 后台服务应用程序的源代码:

package main


import (

    "log"

    "reflect"

    "sync"

    "syscall"


    "github.com/checkgo/win"

    "github.com/kardianos/service"

    "golang.org/x/sys/windows"

)


var logger service.Logger


type program struct {

    exit chan struct{}

}


func (p *program) Start(s service.Service) error {

    if service.Interactive() {

        logger.Info("Running in terminal.")

    } else {

        logger.Info("Running under service manager.")

    }

    p.exit = make(chan struct{})


    // Start should not block. Do the actual work async.

    go p.run()

    return nil

}

func (p *program) run() {

    var wgT sync.WaitGroup

    wgT.Add(1)

    test(&wgT)

    wgT.Wait()

}


func test(wg *sync.WaitGroup) {

    var saAttr win.SECURITY_ATTRIBUTES

    saAttr.NLength = uint32(reflect.TypeOf(syscall.SecurityAttributes{}).Size())

    saAttr.BInheritHandle = win.TRUE

    saAttr.LpSecurityDescriptor = uintptr(0)


    var si syscall.StartupInfo

    si.Cb = uint32(reflect.TypeOf(syscall.SecurityAttributes{}).Size())

    si.Desktop = windows.StringToUTF16Ptr("Winsta0\\default")

    si.Flags = windows.STARTF_USESTDHANDLES

    var hToken windows.Token

    id := win.WTSGetActiveConsoleSessionId()

    err := windows.WTSQueryUserToken(uint32(id), &hToken)

    if err != nil {

        logger.Info(err)

    }

    path := windows.StringToUTF16Ptr("C:\\Users\\cingo\\go\\src\\srv\\agent\\test_agent.exe")


    var pi syscall.ProcessInformation

    syscall.CreateProcessAsUser(syscall.Token(hToken),

        path,

        nil,

        nil,

        nil,

        true,

        windows.CREATE_NO_WINDOW,

        nil,

        nil,

        &si,

        &pi)


}


func (p *program) Stop(s service.Service) error {

    // Stop should not block. Return with a few seconds.

    return nil

}


func main() {

    svcConfig := &service.Config{

        Name:        "GoServiceExampleSimple",

        DisplayName: "Go Service Example",

        Description: "This is an example Go service.",

    }


    prg := &program{}

    s, err := service.New(prg, svcConfig)

    if err != nil {

        log.Fatal(err)

    }

    logger, err = s.Logger(nil)

    if err != nil {

        log.Fatal(err)

    }

    err = s.Run()

    if err != nil {

        logger.Error(err)

    }

}

正在运行的应用程序


package main


import (

    "fmt"

    "github.com/checkgo/win"

    "time"

)


func main() {

    for {

        time.Sleep(time.Second * 1)

        win.OutputDebugString(fmt.Sprintf("%s", "This is test message"))

    }

}


查看完整回答
反对 回复 2022-08-01
  • 2 回答
  • 0 关注
  • 329 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信