github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/libcmdline/fork_windows.go (about)

     1  // Copyright 2018 Keybase, Inc. All rights reserved. Use of
     2  // this source code is governed by the included BSD license.
     3  
     4  //go:build windows
     5  // +build windows
     6  
     7  package libcmdline
     8  
     9  import (
    10  	"os"
    11  	"syscall"
    12  
    13  	"github.com/keybase/client/go/logger"
    14  )
    15  
    16  const flagCreateNewConsole = 0x00000010
    17  
    18  // SpawnDetachedProcess spawns a background process and detech from the calling
    19  // process.
    20  func SpawnDetachedProcess(
    21  	cmd string, args []string, log logger.Logger) (pid int, err error) {
    22  	var files []uintptr
    23  	var devnull *os.File
    24  
    25  	defer func() {
    26  		if err != nil && devnull != nil {
    27  			devnull.Close()
    28  		}
    29  	}()
    30  
    31  	// Failing to open nul is non-fatal here.
    32  	devnull, err = os.OpenFile("nul", os.O_RDONLY, 0)
    33  	if err != nil {
    34  		log.Warning("Cannot open nul: %v", err)
    35  		// 0 is an invalid handle, but more importantly it will
    36  		// not be passed to DuplicateHandle by Go. This works
    37  		// with Go 1.6, but is hacky. This code path is taken
    38  		// only on systems that are broken to begin with...
    39  		files = append(files, 0, 0, 0)
    40  	} else {
    41  		nullfd := devnull.Fd()
    42  		files = append(files, nullfd, nullfd, nullfd)
    43  	}
    44  
    45  	// Create the process with its own console, so it
    46  	// can outlive the parent process's console.
    47  	attr := syscall.ProcAttr{
    48  		Env:   os.Environ(),
    49  		Files: files,
    50  		Sys: &syscall.SysProcAttr{
    51  			HideWindow:    true,
    52  			CreationFlags: flagCreateNewConsole,
    53  		},
    54  	}
    55  
    56  	pid, _, err = syscall.StartProcess(cmd, args, &attr)
    57  	return pid, err
    58  }