Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
305 views
in Technique[技术] by (71.8m points)

c++ - How can I run the application written in Golang as a Windows service

I cannot use the screenshot application that I developed with the Win32 api as a Windows Background service. I install and run it as a Windows background service, I have no problem so far. My problem: The service doesn't give me a printout. Doesn't take a screenshot. I tried making another simple app. I tried sending a message using the OutputDebugStringW function but my problem was not resolved.

  • Can't develop Windows Background application with Win32 api?
  • Why am I having this problem?
  • How can I run my screenshot application as windows background service using win32 api?

My Windows background service that is not producing output

    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)
        }
    }

ScreenShot: DebugView and Windows Services Screen Capture


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

If a service is running in the security context of the LocalSystem account but does not include the SERVICE_INTERACTIVE_PROCESS attribute, it uses the following window station and desktop: Service-0x0-3e7$default. This window station is not interactive, so the service cannot display a user interface. In addition, processes created by the service cannot display a user interface.

Refer: Window Station and Desktop Creation

The interactive window station is the only window station that can display a user interface or receive user input. It is assigned to the logon session of the interactive user, and contains the keyboard, mouse, and display device. It is always named "WinSta0". All other window stations are noninteractive, which means they cannot display a user interface or receive user input.

Refer: Window Stations

It is said that screen you want to capture is in the default desktop of the interactive window station (Winsta0default). You can create a child process in Winsta0default, and the child process is used for screenshots. Use CreateProcessAsUser to call the child process in the service.

Refer to the following C++ code. Although this is not a Go language, I think it is enough to be familiar with the call of 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))
    {
        ...

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...