diff options
Diffstat (limited to 'manager/uiprocess.go')
-rw-r--r-- | manager/uiprocess.go | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/manager/uiprocess.go b/manager/uiprocess.go new file mode 100644 index 00000000..80ac8b30 --- /dev/null +++ b/manager/uiprocess.go @@ -0,0 +1,99 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (C) 2019-2021 WireGuard LLC. All Rights Reserved. + */ + +package manager + +import ( + "errors" + "runtime" + "sync/atomic" + "syscall" + "unsafe" + + "golang.org/x/sys/windows" +) + +type uiProcess struct { + handle uintptr +} + +func launchUIProcess(executable string, args []string, workingDirectory string, handles []windows.Handle, token windows.Token) (*uiProcess, error) { + executable16, err := windows.UTF16PtrFromString(executable) + if err != nil { + return nil, err + } + args16, err := windows.UTF16PtrFromString(windows.ComposeCommandLine(args)) + if err != nil { + return nil, err + } + workingDirectory16, err := windows.UTF16PtrFromString(workingDirectory) + if err != nil { + return nil, err + } + var environmentBlock *uint16 + err = windows.CreateEnvironmentBlock(&environmentBlock, token, false) + if err != nil { + return nil, err + } + defer windows.DestroyEnvironmentBlock(environmentBlock) + attributeList, err := windows.NewProcThreadAttributeList(1) + if err != nil { + return nil, err + } + defer attributeList.Delete() + si := &windows.StartupInfoEx{ + StartupInfo: windows.StartupInfo{Cb: uint32(unsafe.Sizeof(windows.StartupInfoEx{}))}, + ProcThreadAttributeList: attributeList.List(), + } + if len(handles) == 0 { + handles = []windows.Handle{0} + } + attributeList.Update(windows.PROC_THREAD_ATTRIBUTE_HANDLE_LIST, unsafe.Pointer(&handles[0]), uintptr(len(handles))*unsafe.Sizeof(handles[0])) + pi := new(windows.ProcessInformation) + err = windows.CreateProcessAsUser(token, executable16, args16, nil, nil, true, windows.CREATE_DEFAULT_ERROR_MODE|windows.CREATE_UNICODE_ENVIRONMENT|windows.EXTENDED_STARTUPINFO_PRESENT, environmentBlock, workingDirectory16, &si.StartupInfo, pi) + if err != nil { + return nil, err + } + windows.CloseHandle(pi.Thread) + uiProc := &uiProcess{handle: uintptr(pi.Process)} + runtime.SetFinalizer(uiProc, (*uiProcess).release) + return uiProc, nil +} + +func (p *uiProcess) release() error { + handle := windows.Handle(atomic.SwapUintptr(&p.handle, uintptr(windows.InvalidHandle))) + if handle == windows.InvalidHandle { + return nil + } + err := windows.CloseHandle(handle) + if err != nil { + return err + } + runtime.SetFinalizer(p, nil) + return nil +} + +func (p *uiProcess) Wait() (uint32, error) { + handle := windows.Handle(atomic.LoadUintptr(&p.handle)) + s, err := windows.WaitForSingleObject(handle, syscall.INFINITE) + switch s { + case windows.WAIT_OBJECT_0: + case windows.WAIT_FAILED: + return 0, err + default: + return 0, errors.New("unexpected result from WaitForSingleObject") + } + var exitCode uint32 + err = windows.GetExitCodeProcess(handle, &exitCode) + if err != nil { + return 0, err + } + p.release() + return exitCode, nil +} + +func (p *uiProcess) Kill() error { + return windows.TerminateProcess(windows.Handle(atomic.LoadUintptr(&p.handle)), 1) +} |