获取syscall.CreateProcess的输出

时间:2019-05-23 09:48:03

标签: windows go

这是我的代码:

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)

现在,我想获取已执行代码的输出结果。反正有吗?

1 个答案:

答案 0 :(得分:4)

正如问题的评论中所说,执行流程的最佳方式是使用 os/exec 包。但是,如果您需要在 Windows 上非常具体的东西,您可以使用 sys/windows 包。

为了让您的子进程与您的父进程通信,您必须建立管道通信。对于完全相同的问题,您可以在此 C++ 答案中找到有关此问题的解释:How to read output from cmd.exe using CreateProcess() and CreatePipe()

这是获取子进程输出的解决方案。


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
}