golang.zx2c4.com/wireguard/windows@v0.5.4-0.20230123132234-dcc0eb72a04b/manager/uiprocess.go (about) 1 /* SPDX-License-Identifier: MIT 2 * 3 * Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved. 4 */ 5 6 package manager 7 8 import ( 9 "errors" 10 "runtime" 11 "sync/atomic" 12 "syscall" 13 "unsafe" 14 15 "golang.org/x/sys/windows" 16 ) 17 18 type uiProcess struct { 19 handle uintptr 20 } 21 22 func launchUIProcess(executable string, args []string, workingDirectory string, handles []windows.Handle, token windows.Token) (*uiProcess, error) { 23 executable16, err := windows.UTF16PtrFromString(executable) 24 if err != nil { 25 return nil, err 26 } 27 args16, err := windows.UTF16PtrFromString(windows.ComposeCommandLine(args)) 28 if err != nil { 29 return nil, err 30 } 31 workingDirectory16, err := windows.UTF16PtrFromString(workingDirectory) 32 if err != nil { 33 return nil, err 34 } 35 var environmentBlock *uint16 36 err = windows.CreateEnvironmentBlock(&environmentBlock, token, false) 37 if err != nil { 38 return nil, err 39 } 40 defer windows.DestroyEnvironmentBlock(environmentBlock) 41 attributeList, err := windows.NewProcThreadAttributeList(1) 42 if err != nil { 43 return nil, err 44 } 45 defer attributeList.Delete() 46 si := &windows.StartupInfoEx{ 47 StartupInfo: windows.StartupInfo{Cb: uint32(unsafe.Sizeof(windows.StartupInfoEx{}))}, 48 ProcThreadAttributeList: attributeList.List(), 49 } 50 if len(handles) == 0 { 51 handles = []windows.Handle{0} 52 } 53 attributeList.Update(windows.PROC_THREAD_ATTRIBUTE_HANDLE_LIST, unsafe.Pointer(&handles[0]), uintptr(len(handles))*unsafe.Sizeof(handles[0])) 54 pi := new(windows.ProcessInformation) 55 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) 56 if err != nil { 57 return nil, err 58 } 59 windows.CloseHandle(pi.Thread) 60 uiProc := &uiProcess{handle: uintptr(pi.Process)} 61 runtime.SetFinalizer(uiProc, (*uiProcess).release) 62 return uiProc, nil 63 } 64 65 func (p *uiProcess) release() error { 66 handle := windows.Handle(atomic.SwapUintptr(&p.handle, uintptr(windows.InvalidHandle))) 67 if handle == windows.InvalidHandle { 68 return nil 69 } 70 err := windows.CloseHandle(handle) 71 if err != nil { 72 return err 73 } 74 runtime.SetFinalizer(p, nil) 75 return nil 76 } 77 78 func (p *uiProcess) Wait() (uint32, error) { 79 handle := windows.Handle(atomic.LoadUintptr(&p.handle)) 80 s, err := windows.WaitForSingleObject(handle, syscall.INFINITE) 81 switch s { 82 case windows.WAIT_OBJECT_0: 83 case windows.WAIT_FAILED: 84 return 0, err 85 default: 86 return 0, errors.New("unexpected result from WaitForSingleObject") 87 } 88 var exitCode uint32 89 err = windows.GetExitCodeProcess(handle, &exitCode) 90 if err != nil { 91 return 0, err 92 } 93 p.release() 94 return exitCode, nil 95 } 96 97 func (p *uiProcess) Kill() error { 98 handle := windows.Handle(atomic.LoadUintptr(&p.handle)) 99 if handle == windows.InvalidHandle { 100 return nil 101 } 102 return windows.TerminateProcess(handle, 1) 103 }