首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

如何使用CreateProcess()和CreatePipe()从cmd.exe读取输出

CreateProcess()CreatePipe() 是 Windows API 中的两个函数,用于创建新进程并与其进行通信。CreateProcess() 用于启动一个新进程,而 CreatePipe() 用于创建一个管道,以便在新进程和父进程之间传输数据。

基础概念

  1. CreateProcess():
    • 用于创建一个新的进程和它的主线程。
    • 可以指定要执行的程序文件和命令行参数。
    • 返回一个 PROCESS_INFORMATION 结构体,包含新进程的句柄等信息。
  • CreatePipe():
    • 用于创建一个匿名管道,用于进程间通信。
    • 返回两个句柄,一个用于读取,一个用于写入。
    • 管道是单向的,通常需要创建两个管道来实现双向通信。

相关优势

  • 进程隔离: 通过创建新进程,可以隔离主程序和新进程的资源,避免相互影响。
  • 数据传输: 使用管道可以在进程间安全地传输数据,支持异步读写。

类型

  • 匿名管道: 用于本地进程间通信,不支持跨网络传输。
  • 命名管道: 支持跨网络传输,但需要一个名称来标识管道。

应用场景

  • 自动化脚本执行: 通过读取命令行工具的输出,自动化执行一些任务。
  • 调试和监控: 实时获取进程的输出信息,进行调试和监控。

示例代码

以下是一个简单的示例,展示如何使用 CreateProcess()CreatePipe()cmd.exe 读取输出:

代码语言:txt
复制
#include <windows.h>
#include <iostream>

int main() {
    HANDLE hChildStdOutRead, hChildStdOutWrite;
    SECURITY_ATTRIBUTES saAttr;

    // Set the bInheritHandle flag so pipe handles are inherited.
    saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
    saAttr.bInheritHandle = TRUE;
    saAttr.lpSecurityDescriptor = NULL;

    // Create a pipe for the child process's STDOUT.
    if (!CreatePipe(&hChildStdOutRead, &hChildStdOutWrite, &saAttr, 0)) {
        std::cerr << "CreatePipe Error: " << GetLastError() << std::endl;
        return 1;
    }

    // Ensure the read handle to the pipe for STDOUT is not inherited.
    if (!SetHandleInformation(hChildStdOutRead, HANDLE_FLAG_INHERIT, 0)) {
        std::cerr << "SetHandleInformation Error: " << GetLastError() << std::endl;
        return 1;
    }

    // Create the child process.
    PROCESS_INFORMATION piProcInfo;
    STARTUPINFO siStartInfo;
    BOOL bSuccess = FALSE;

    // Set up members of the PROCESS_INFORMATION structure.
    ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION));

    // Set up members of the STARTUPINFO structure.
    ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
    siStartInfo.cb = sizeof(STARTUPINFO);
    siStartInfo.hStdOutput = hChildStdOutWrite;
    siStartInfo.hStdError = hChildStdOutWrite;
    siStartInfo.dwFlags |= STARTF_USESTDHANDLES;

    // Create the child process.
    bSuccess = CreateProcess(NULL,
                             "cmd.exe /c dir",     // command line 
                             NULL,                   // process security attributes 
                             NULL,                   // primary thread security attributes 
                             TRUE,                   // handles are inherited 
                             0,                      // creation flags 
                             NULL,                   // use parent's environment 
                             NULL,                   // use parent's current directory 
                             &siStartInfo,           // STARTUPINFO pointer 
                             &piProcInfo);           // receives PROCESS_INFORMATION 

    // If an error occurs, exit the application. 
    if (!bSuccess) {
        std::cerr << "CreateProcess Error: " << GetLastError() << std::endl;
        return 1;
    }

    // Close the write end of the pipe before reading from the read end of the pipe.
    CloseHandle(hChildStdOutWrite);

    // Read output from the child process's pipe for STDOUT.
    CHAR chBuf[4096];
    DWORD dwRead;
    std::string strOutput;

    while (ReadFile(hChildStdOutRead, chBuf, sizeof(chBuf), &dwRead, NULL) && dwRead != 0) {
        strOutput.append(chBuf, dwRead);
    }

    // Close the read handle.
    CloseHandle(hChildStdOutRead);

    // Wait until child process exits.
    WaitForSingleObject(piProcInfo.hProcess, INFINITE);

    // Close process and thread handles.
    CloseHandle(piProcInfo.hProcess);
    CloseHandle(piProc::hThread);

    // Output the result.
    std::cout << "Output from cmd.exe:\n" << strOutput << std::endl;

    return 0;
}

参考链接

常见问题及解决方法

  1. 管道句柄继承问题:
    • 确保在 CreatePipe() 后调用 SetHandleInformation() 来防止读取句柄被继承。
    • 示例代码中已包含此步骤。
  • 读取管道数据时的阻塞问题:
    • 使用 ReadFile() 读取管道数据时,可能会阻塞等待数据。可以使用超时参数或异步读取来解决。
    • 示例代码中使用循环读取直到没有数据。
  • 进程等待问题:
    • 在读取完管道数据后,需要等待子进程结束,否则可能会导致子进程成为僵尸进程。
    • 示例代码中使用 WaitForSingleObject() 等待子进程结束。

通过以上步骤和示例代码,你可以实现从 cmd.exe 读取输出的功能。

页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

领券