2 回答
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))
{
...
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"))
}
}
- 2 回答
- 0 关注
- 329 浏览
添加回答
举报