猿问

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

我无法使用我使用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 服务屏幕捕获


偶然的你
浏览 331回答 2
2回答

慕码人2483693

如果服务在 LocalSystem 帐户的安全上下文中运行,但不包括SERVICE_INTERACTIVE_PROCESS属性,则它使用以下窗口工作站和桌面:Service-0x0-3e7$\default。此窗口站不是交互式的,因此服务无法显示用户界面。此外,由服务创建的进程无法显示用户界面。参考:窗口站和桌面创建交互式窗口站是唯一可以显示用户界面或接收用户输入的窗口站。它被分配给交互式用户的登录会话,并包含键盘、鼠标和显示设备。它总是被命名为“WinSta0”。所有其他窗口站都是非交互式的,这意味着它们无法显示用户界面或接收用户输入。参考:窗口站据说您要捕获的屏幕位于交互式窗口站的默认桌面(Winsta0\default)。您可以在 中创建子进程,子进程用于屏幕截图。使用&nbsp;CreateProcessAsUser&nbsp;调用服务中的子进程。Winsta0\default请参阅以下C++代码。虽然这不是一门围棋语言,但我认为熟悉winapi的呼唤就足够了。DWORD WINAPI ServiceWorkerThread(LPVOID lpParam){&nbsp; &nbsp; OutputDebugString(_T("My Sample Service: ServiceWorkerThread: Entry"));&nbsp; &nbsp; WCHAR station[] = L"Winsta0\\default";&nbsp; &nbsp; SECURITY_ATTRIBUTES saAttr;&nbsp; &nbsp; saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);&nbsp; &nbsp; saAttr.bInheritHandle = TRUE;&nbsp; &nbsp; saAttr.lpSecurityDescriptor = NULL;&nbsp; &nbsp; &nbsp;&nbsp; &nbsp; STARTUPINFO si;&nbsp; &nbsp; ZeroMemory(&si, sizeof(STARTUPINFO));&nbsp; &nbsp; si.cb = sizeof(STARTUPINFO);&nbsp; &nbsp; si.lpDesktop = station;&nbsp; &nbsp; si.dwFlags = STARTF_USESTDHANDLES;&nbsp; &nbsp; PROCESS_INFORMATION pi;&nbsp; &nbsp; HANDLE hToken;&nbsp; &nbsp; bool err = WTSQueryUserToken(WTSGetActiveConsoleSessionId(), &hToken);&nbsp; &nbsp; WCHAR path[] = L"D:\\child.exe";&nbsp; //child.exe is used to take screenshots&nbsp; &nbsp; if (CreateProcessAsUser(hToken, path, NULL, 0, 0, true, CREATE_NO_WINDOW, 0, 0, &si, &pi))&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; ...

慕盖茨4494581

使用CreateProcessAsUser函数解决。我用来解决问题的GOO源代码。Windows 后台服务应用程序的源代码:package mainimport (&nbsp; &nbsp; "log"&nbsp; &nbsp; "reflect"&nbsp; &nbsp; "sync"&nbsp; &nbsp; "syscall"&nbsp; &nbsp; "github.com/checkgo/win"&nbsp; &nbsp; "github.com/kardianos/service"&nbsp; &nbsp; "golang.org/x/sys/windows")var logger service.Loggertype program struct {&nbsp; &nbsp; exit chan struct{}}func (p *program) Start(s service.Service) error {&nbsp; &nbsp; if service.Interactive() {&nbsp; &nbsp; &nbsp; &nbsp; logger.Info("Running in terminal.")&nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; logger.Info("Running under service manager.")&nbsp; &nbsp; }&nbsp; &nbsp; p.exit = make(chan struct{})&nbsp; &nbsp; // Start should not block. Do the actual work async.&nbsp; &nbsp; go p.run()&nbsp; &nbsp; return nil}func (p *program) run() {&nbsp; &nbsp; var wgT sync.WaitGroup&nbsp; &nbsp; wgT.Add(1)&nbsp; &nbsp; test(&wgT)&nbsp; &nbsp; wgT.Wait()}func test(wg *sync.WaitGroup) {&nbsp; &nbsp; var saAttr win.SECURITY_ATTRIBUTES&nbsp; &nbsp; saAttr.NLength = uint32(reflect.TypeOf(syscall.SecurityAttributes{}).Size())&nbsp; &nbsp; saAttr.BInheritHandle = win.TRUE&nbsp; &nbsp; saAttr.LpSecurityDescriptor = uintptr(0)&nbsp; &nbsp; var si syscall.StartupInfo&nbsp; &nbsp; si.Cb = uint32(reflect.TypeOf(syscall.SecurityAttributes{}).Size())&nbsp; &nbsp; si.Desktop = windows.StringToUTF16Ptr("Winsta0\\default")&nbsp; &nbsp; si.Flags = windows.STARTF_USESTDHANDLES&nbsp; &nbsp; var hToken windows.Token&nbsp; &nbsp; id := win.WTSGetActiveConsoleSessionId()&nbsp; &nbsp; err := windows.WTSQueryUserToken(uint32(id), &hToken)&nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; logger.Info(err)&nbsp; &nbsp; }&nbsp; &nbsp; path := windows.StringToUTF16Ptr("C:\\Users\\cingo\\go\\src\\srv\\agent\\test_agent.exe")&nbsp; &nbsp; var pi syscall.ProcessInformation&nbsp; &nbsp; syscall.CreateProcessAsUser(syscall.Token(hToken),&nbsp; &nbsp; &nbsp; &nbsp; path,&nbsp; &nbsp; &nbsp; &nbsp; nil,&nbsp; &nbsp; &nbsp; &nbsp; nil,&nbsp; &nbsp; &nbsp; &nbsp; nil,&nbsp; &nbsp; &nbsp; &nbsp; true,&nbsp; &nbsp; &nbsp; &nbsp; windows.CREATE_NO_WINDOW,&nbsp; &nbsp; &nbsp; &nbsp; nil,&nbsp; &nbsp; &nbsp; &nbsp; nil,&nbsp; &nbsp; &nbsp; &nbsp; &si,&nbsp; &nbsp; &nbsp; &nbsp; &pi)}func (p *program) Stop(s service.Service) error {&nbsp; &nbsp; // Stop should not block. Return with a few seconds.&nbsp; &nbsp; return nil}func main() {&nbsp; &nbsp; svcConfig := &service.Config{&nbsp; &nbsp; &nbsp; &nbsp; Name:&nbsp; &nbsp; &nbsp; &nbsp; "GoServiceExampleSimple",&nbsp; &nbsp; &nbsp; &nbsp; DisplayName: "Go Service Example",&nbsp; &nbsp; &nbsp; &nbsp; Description: "This is an example Go service.",&nbsp; &nbsp; }&nbsp; &nbsp; prg := &program{}&nbsp; &nbsp; s, err := service.New(prg, svcConfig)&nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; log.Fatal(err)&nbsp; &nbsp; }&nbsp; &nbsp; logger, err = s.Logger(nil)&nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; log.Fatal(err)&nbsp; &nbsp; }&nbsp; &nbsp; err = s.Run()&nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; logger.Error(err)&nbsp; &nbsp; }}正在运行的应用程序package mainimport (&nbsp; &nbsp; "fmt"&nbsp; &nbsp; "github.com/checkgo/win"&nbsp; &nbsp; "time")func main() {&nbsp; &nbsp; for {&nbsp; &nbsp; &nbsp; &nbsp; time.Sleep(time.Second * 1)&nbsp; &nbsp; &nbsp; &nbsp; win.OutputDebugString(fmt.Sprintf("%s", "This is test message"))&nbsp; &nbsp; }}
随时随地看视频慕课网APP

相关分类

Go
我要回答