Natasha
Natasha

Reputation: 1

Get output of syscall.CreateProcess

This is my code:

var command = "ping 127.0.0.1 && exit"
var sI syscall.StartupInfo
var pI syscall.ProcessInformation

argv := syscall.StringToUTF16Ptr(os.Getenv("windir")+"\\system32\\cmd.exe /C " + command)
syscall.CreateProcess(
    nil,
    argv,
    nil,
    nil,
    true,
    0x08000000,
    nil,
    nil,
    &sI,
    &pI)

Now I want get output result of executed code. Is there anyway?

Upvotes: 0

Views: 974

Answers (1)

Godineau Félicie
Godineau Félicie

Reputation: 438

As said in the comments of the question, the best way to execute a process is to use the os/exec package. But, if you need something very specific on windows, you can use the sys/windows package.

In order for your child process to communicate with you parent process, you must establish a piped communication. You can find explanations about this in this C++ answer for quite the same issue : How to read output from cmd.exe using CreateProcess() and CreatePipe()

Here is the solution in go to get your child process output.


func main() {
    var command = "ping 127.0.0.1 && exit"

    var (
        sI syscall.StartupInfo
        pI syscall.ProcessInformation

        stdOutPipeRead  windows.Handle
        stdOutPipeWrite windows.Handle
        stdErrPipeRead  windows.Handle
        stdErrPipeWrite windows.Handle
        stdInPipeRead   windows.Handle
        stdInPipeWrite  windows.Handle
    )

    sa := windows.SecurityAttributes {
        Length:             uint32(unsafe.Sizeof(windows.SecurityAttributes{})),
        SecurityDescriptor: nil,
        InheritHandle:      1, //true
    }

    windows.CreatePipe(&stdOutPipeRead, &stdOutPipeWrite, &sa, 0)
    windows.CreatePipe(&stdErrPipeRead, &stdErrPipeWrite, &sa, 0)
    windows.CreatePipe(&stdWritePipeRead, &stdWritePipeWrite, &sa, 0)

    sI.Flags = windows.STARTF_USESTDHANDLES
    sI.StdErr = stdErrPipeWrite
    sI.StdOutput = stdOutPipeWrite
    sI.StdInput = stdOutPipeRead

    argv := windows.StringToUTF16Ptr(os.Getenv("windir")+"\\system32\\cmd.exe /C " +     command)
    windows.CreateProcess(
        nil,
        argv,
        nil,
        nil,
        true,
        0x08000000,
        nil,
        nil,
        &sI,
        &pI)

    windows.CloseHandle(stdOutPipeWrite)
    windows.CloseHandle(stdErrPipeWrite)
    windows.CloseHandle(stdInPipeWrite)

    stdErr := readPipe(stdErrPipeRead)
    stdOut := readPipe(stdOutPipeRead)

    windows.CloseHandle(stdOutPipeRead)
    windows.CloseHandle(stdErrPipeRead)
    windows.CloseHandle(stdInPipeWrite)
}

func readPipe(pipe windows.Handle) string {
    result := ""
    buf := make([]byte, 1024+1)
    var read int = 0
    err := windows.ReadFile(pipe, &buf[0], 1024, &read), 0)
    // read until you receive a broken pipe error
    for err == nil {
        result += string(buf[:read])
        err = windows.ReadFile(pipe, &buf[0], 1024, &read), 0)
    }
    return result
}

Upvotes: 4

Related Questions