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  }